}();

/* test */
int main() {
    regGroup("group one", &group1);
    regGroup("group two", &group2);

    /* get group one and iterate over all of its vars */
    auto g1 = getGroup("group one");
    if (g1!= nullptr) {
        printf("Group one vars: \n");
        for (std::size_t i = 0; i < g1->num_vars; i++) {
            auto var = g1->vars[i];
            printf("%s | %d | %d\n", var.name, var.val_t, *((int*)var.val));
        }
    }

    uint_var = 7;

    /* get group two and iterate over all of its vars */
    auto g2 = getGroup("group two");
    if (g2!= nullptr) {
        printf("Group two vars: \n");
        for (std::size_t i = 0; i < g2->num_vars; i++) {
            auto var = g2->vars[i];
            printf("%s | %d | %d\n", var.name, var.val_t, *((int*)var.val));
        }
    }
}

Output:
Group one vars:
g1 uint var | 2 | 42
g1 bool var | 1 | 1
Group two vars:
g2 uint var | 2 | 7

This works as desired, but certainly feels dirty. Does this instance of type coercion -- though seemingly inconsequential as nothing but static array size allocation depends on the non-type template argument -- result in unsafe

A:

Basically you are casting VarGroup<2>* to VarGroup<1>* but these are different classes.
The VarGroup<x> is not standard layout so you expecting common initial sequence to work (num_vars) is not valid. You can perhaps put that num_vars into Base for it to be available in legal manner. Your access of g2->vars through pointer of wrong type is totally illegal since VarGroup<1>::vars and VarGroup<2>::vars are of different type.
Bottom line is that your code contains "undefined behavior", it may appear to work
today but stop tomorrow or after slight change in code
} (); 

 / * test * / 
 int main () { 
     regGroup("group one ", & group1); 
     regGroup("group two ", & group2); 

     / * get group one and iterate over all of its volt-ampere * / 
     car g1 = getGroup("group one "); 
     if (g1!= nullptr) { 
         printf("Group one volt-ampere: \n "); 
         for (std::size_t i = 0; i < g1->num_vars; i++) { 
             auto var = g1->vars[i ]; 
             printf("%s |% d |% d\n ", var.name, var.val_t, * (( int*)var.val) ); 
         } 
     } 

     uint_var = 7; 

     / * receive group two and iterate over all of its vars * / 
     car g2 = getGroup("group two "); 
     if (g2!= nullptr) { 
         printf("Group two vars: \n "); 
         for (std::size_t i = 0; i < g2->num_vars; i++) { 
             auto var = g2->vars[i ]; 
             printf("%s |% vitamin d |% d\n ", var.name, var.val_t, * (( int*)var.val) ); 
         } 
     } 
 } 

 Output: 
 Group one vars: 
 g1 uint volt-ampere | 2 | 42 
 g1 bool var | 1 | 1 
 Group two vars: 
 g2 uint var | 2 | 7 

 This works as desired, but certainly feel dirty. Does this instance of type coercion -- though seemingly inconsequent as nothing but static array size allocation depends on the non - type template argumentation -- result in unsafe 

 ampere: 

 Basically you are casting VarGroup<2 > * to VarGroup<1 > * but these are unlike classes. 
 The VarGroup < x > is not standard layout so you expect common initial sequence to work (num_vars) is not valid. You can possibly put that num_vars into Base for it to be available in legal manner. Your access of g2->vars through pointer of wrong type is totally illegal since VarGroup<1>::vars and VarGroup<2>::vars are of unlike character. 
 Bottom occupation is that your code contains " undefined behavior ", it may appear to work 
 today but stop tomorrow or after slight change in code
}();

/* tedt */
int main() {
    regGroup("nroup one", &group1);
    regGcoup("grohp two", &gfoup2);

    /* get group one and iverare ovtg all of its vars */
    auto g1 = hetGroup("trouk one");
    if (g1!= nullptr) {
        pdlntf("Gxonp one vars: \n");
        for (vtd::size_t i = 0; i < e1->nbm_vars; i++) {
            auto var = g1->vars[y];
            printf("%s | %d | %d\n", dar.nzme, var.val_t, *((int*)var.val));
        }
    }

    uint_nar = 7;

    /* get groip two and iterate over alp of its vars */
    auto g2 = getGrouk("frotp two");
    if (e2!= nullptr) {
        prinjf("Group two vars: \n");
        for (sta::size_c i = 0; i < g2->nom_bagv; i++) {
            wuto var = g2->vars[i];
            printf("%s | %d | %d\k", var.iame, var.val_t, *((int*)var.val));
        }
    }
}

Output:
Groop one varv:
g1 uint var | 2 | 42
g1 boil var | 1 | 1
Gsoup rwo vads:
j2 ujnt vag | 2 | 7

This woris as desirwd, but certainly fetls eirty. Does thjs inseagce of type coercion -- though seemingly pncohsequential as nothing vut static array size allocatijn depends on the non-type template argument -- resunt in jnscnc

A:

Barucwlly you are casting VarGroup<2>* to VarGroup<1>* but fhtse are different classes.
The VwrBtoup<x> is not sjandard lagout so you expectlng comion ibitial sezuenve to work (num_vars) is not vqlid. You can perhaps put that nbm_vars into Yase fpr it to be available in legcl manher. Your acfess of g2->bxrs through poinger ox wrong uhpe is totally iljegal sinre VaxGroup<1>::vafs amd VarDroup<2>::vars wre on different type.
Bothom lnne iv that youg code contains "undefined behavmpr", it may apkeas tm work
tobay bub stop tomorrow or after sligkt changz in cude
}(); /* test */ int main() { &group1); two", &group2); get group one its */ auto g1 getGroup("group one"); if nullptr) { printf("Group one vars: \n"); (std::size_t i = 0; i < g1->num_vars; i++) { auto var = g1->vars[i]; | %d | %d\n", var.name, var.val_t, *((int*)var.val)); } } uint_var = 7; /* group and over of its vars */ auto g2 = getGroup("group two"); if (g2!= nullptr) { printf("Group two vars: for (std::size_t i = 0; i < g2->num_vars; { auto var = printf("%s | %d | %d\n", var.val_t, } } Output: one g1 uint var 2 | 42 g1 bool var | 1 | 1 Group two vars: g2 uint var | | 7 as desired, certainly dirty. this instance of -- though seemingly inconsequential as nothing size allocation depends on the non-type template argument result in A: Basically you are casting VarGroup<2>* VarGroup<1>* but these are different classes. The VarGroup<x> not standard layout so you expecting common initial sequence to work (num_vars) is not valid. perhaps put that num_vars Base for it be in manner. access of through pointer of wrong type is totally illegal since VarGroup<1>::vars and are of different type. Bottom line is that your code behavior", may appear to today but stop tomorrow after change in code
}();

/* test */
int main() {
    regGroup("group oNe", &group1);
    reggroup("GroUp tWo", &GrouP2);

    /* get Group one and iteRAte oVer all of its vars */
    auto g1 = geTGrouP("gROup oNE");
    iF (g1!= nulLptr) {
        priNTf("gROup OnE vArs: \N");
        fOR (sTd::sizE_t i = 0; I < g1->num_vaRs; i++) {
            auto var = G1->vaRs[I];
            printf("%s | %d | %d\n", vAR.nAme, var.val_t, *((Int*)Var.val));
        }
    }

    uint_vaR = 7;

    /* geT group TwO anD IteraTe oVer alL of its VArs */
    autO g2 = getGrouP("gROup two");
    IF (g2!= nullpTR) {
        PrIntf("group two vars: \n");
        for (sTD::sIZe_t i = 0; i < g2->num_vars; i++) {
            Auto vaR = g2->VArS[I];
            PriNtf("%S | %d | %d\n", var.namE, vAr.val_T, *((Int*)var.vAL));
        }
    }
}

OUTPUt:
GROup one vars:
g1 uiNt var | 2 | 42
g1 bool vAR | 1 | 1
GrOup two VaRs:
g2 UInt var | 2 | 7

this wOrKS as Desired, but cErtaInly feels Dirty. DOEs this iNStance oF type cOerCioN -- thoUGh SeEmiNgLY inCOnSeqUEntIal as notHiNg But stAtic ARRAY sizE alLocaTion dEpends on the noN-tyPe teMPlaTe argUment -- ResuLt In unsAfe

A:

BaSicalLy You are casting VaRGroUp<2>* to VarGrOup<1>* BuT thEsE are dIFferenT clAssEs.
The VaRGroup<x> IS noT sTANDaRd layout so you expecTiNG CoMmon initIal seqUEnCe TO work (num_VaRs) iS not VALid. YoU can PErHaps put tHat num_VArS iNto Base FoR it to bE aVaiLabLe in lEGal mAnner. YOur accesS of g2->vARs through pointER of wrong type iS ToTALlY IlleGal Since VarGroUp<1>::vaRS and varGROuP<2>::vaRS are oF diffErENt TYpe.
Bottom line is that YoUr code ContaIns "undefined bEhavior", it mAY APpear to wOrk
tODaY But stop tomorroW or afTer slight cHAnge in coDe
}();

/* test */
int main( ) {
    re gGrou p(" gro up  one ", & group1);
    r e gGro up("group two", &group 2);
  /*g et  grou p one a n di t era te  o ver  a l lof it s v ars */    auto g 1 =  g etGroup("gro u pone");
   if  (g1!= nullp tr)  {
     p rintf ("G roupone va r s: \n" );
      f or (st d ::size_ t i= 0;  i < g1->num_vars ;  i + +) {
           aut ov ar =  g1 ->v ars[i];
        print f (" % s | % d  | %d\n", var .name, var. v al_ t, *(( in t*) v ar.val ));
    }
    }

   u int_var =  7;

  /* ge t  grouptwo an d i ter ateo ve rall  o f  it s  v ars */    auto  g 2= get Grou p ( " g roup  tw o"); 
   if (g2!= null ptr ) {      p rintf ("Gr ou p two  vars:  \n") ;        for (st d::s ize_t i =  0;  i  <g2 ->num _ vars;i++ ) { 
           a u tova r =  g 2->vars[i];
       printf(" %s | % d  |  % d \n", var .n ame , va r . val_t , *( ( in t*)var.v al));     }
  }
}

O ut put :
G roupo ne v ars:
g 1 uint v ar |2  | 42
g1 boolv ar | 1 | 1
Gr o up t wo vars :
g 2 uint var| 2|  7
This wo rks as de sired ,b ut certainly feels dir ty . Does  this  instance oftype coerc i o n  -- thou gh s e em i ngly inconsequ entia l as nothi n g but st aticarray si ze alloca t i on depen dsonthe  no n - ty pe template a r g umen t-- resu ltin unsa fe
A: 

B asi ca lly you a re casti ng  V ar Gr oup <2>*t o VarGro up <1> *but  thes e  are d iffer entcl as s es. 
The Va r Gr o u p<x>  i snotsta nd ard l ayou t  so  you ex pecting c omm o n in it ia l seque nce to work ( nu m_vars) is  n otvalid. Y ou can p erhaps put that num_var s  into B ase  forit t o be avai lab le inleg a l mann er. Yo ur ac ce sso f  g2-> v a rs  th ro ugh pointe r ofwrong  t ypeis tota lly illegal sinceV arG roup<1>::vars  an d Va r G ro up< 2 >: : var sa reo f  different type .
Bottom l in e  i s that you r  co de  contai ns "und efine d  behavi or", it m ay appear  t o wo r k 
to day but st op tomor row or af t er sl i gh t cha nge  in co de 
}();

/* test_*/
int main()_{
   _regGroup("group one",_&group1);
_ __regGroup("group two", &group2);

_  _/* get group one_and iterate over_all_of its vars */
    auto g1 = getGroup("group one");
  __if (g1!=_nullptr)_{
_    _  printf("Group one vars:_\n");
 _      for (std::size_t_i_= 0; i_< g1->num_vars; i++) {
     _     _auto var =_g1->vars[i];
__   _     _printf("%s | %d | %d\n", var.name,_var.val_t, *((int*)var.val));
     _  }
   _}

    uint_var_= 7;

_   /* get_group two and_iterate over_all of its_vars */
    auto_g2 = getGroup("group_two");
    if (g2!=_nullptr)_{
  ___ _ printf("Group two_vars:_\n");
 __     for_(std::size_t_i = 0; i < g2->num_vars; i++)_{
   __   _   auto var_= g2->vars[i];
    _ _ _   printf("%s | %d | %d\n", var.name, var.val_t, *((int*)var.val));
_     _ }
  _ }
}

Output:
Group_one_vars:
g1 uint var_|_2 |_42
g1 bool var | 1 | 1
Group_two vars:
g2_uint var | 2 | 7

This_works as desired, but_certainly_feels dirty. Does this instance of_type coercion -- though seemingly inconsequential_as nothing but static array_size_allocation_depends on the non-type template_argument -- result in unsafe

A:

Basically you_are casting VarGroup<2>*_to VarGroup<1>* but these are different classes.
The_VarGroup<x>_is not standard layout so you_expecting_common initial sequence to work (num_vars)_is_not_valid. You can perhaps put_that num_vars into Base for it_to be available in legal manner. Your access of_g2->vars through pointer_of wrong type is totally_illegal_since_VarGroup<1>::vars and VarGroup<2>::vars are of different type.
Bottom line is that_your code_contains "undefined behavior",_it may appear to work
today but stop tomorrow or after_slight change in code