C ++ 17 vs C ++ 14 - kui-konspekt

Meil on hea meel näha, et if-constexpr viis C ++ 17-ni. Saate seda ise proovida, kasutades praegust klanni pagasiruumi.

Selles ajaveebipostituses vaatame uuesti üle mõne C ++ 14 koodi ja proovime uut funktsiooni kasutada.

Kui teil pole if-contexpr-i, peate sageli kasutama metaprogrammeerimise tehnikaid, kasutades malli mustrite sobitamist, ülekoormuse eraldamist ja SFINAE-d.

Näide 1 - n-nda argi saamine

Paljud mallide metaprogrammid töötavad variadiik-tüüpi loendites. C ++ 14 puhul rakendatakse argumendiloendite n-nda tüübi hankimine sageli järgmisel viisil:

mall 
struct Arg {
 mall 
 constexpr autojuht () (X x, Xs… xs) {
   tagasi Arg  {} (xs…);
 }
};
mall <>
struct Arg <0> {
 mall 
 constexpr autojuht () (X x, Xs…) {
   tagasi x;
 }
};
mall 
constexpr auto arg = Arg  {};
// arg <2> (0,1,2,3,4,5) == 2;

C ++ 17 muudab selle pisut intuitiivsemaks:

mall 
struct Hangi {
 mall 
 constexpr autojuht () (X x, Xs… xs) {
   kui constexpr (n> suurus… (xs)) {
     tagasi;
   } muu, kui constexpr (n> 0) {
     return Hangi  {} (xs…);
   } veel {
     tagasi x;
   }
 }
};

Näide 2 - API - varjestus

Mõnikord soovite toetada alternatiivset API-d. C ++ 14 pakub lihtsat võimalust kontrollida, kas eset saab teatud viisil kasutada:

mall 
constexpr toetab automaatselt API (T x) -> deklüüpi (x.Method1 (), x.Method2 (), true_type {}) {
 tagasi {};
}
constexpr toetab automaatselt API (…) -> false_type {
 tagasi {};
}

Kohandatud käitumise rakendamist rakenduses C ++ 14 saab teha nii:

mall 
automaatne arvutamine (T x) -> deklüüp (enable_if_t  {}) {
 tagastama x.meetod ();
}
mall 
automaatne arvutamine (T x) -> deklüüp (enable_if_t  {}) {
 tagasi 0;
}

C ++ 17:

mall 
int arvuta (T x) {
 kui constexpr (toetab API (T {})) {
   // kompileeritakse ainult siis, kui tingimus on tõene
   tagastama x.meetod ();
 } veel {
   tagasi 0;
 }
}

See on väga mugav, kuna semantiliselt koosnev kood ei ole hajutatud mitmele funktsioonile. Lisaks saate määratleda isegi if-constexpr-i sisaldavad lambad.

Näide 3 - kompileerimisaja algoritmi valimine

Sageli peate leidma parima algoritmi, mis põhineb tüübi reeglite ja omaduste komplektil. Lahendusi on palju. Näiteks kasutab STL mõnede iteraatorite jaoks õige algoritmi valimiseks TypeTagsi.

struct FooTag {};
struct BarTag {};
automaatne foldFF (…) {}
automaatne foldFB (…) {}
automaatne foldBF (…) {}
automaatne voltimineBB (…) {}
struct A {
 / *… * /
 kasutades silti = FooTag;
};
Struktuur B {
 / *… * /
 kasutades tag = BarTag;
};
mall 
automaatne voltimine (L l, R r, FooTag, BarTag) {foldFB (l, r); }
/ * veel saatmisfunktsioone * /
mall 
automaatne voltimine (L l, R r) {
 tagasivolt korda (l, r,
 tüüpnimi L :: silt {},
 tüüpnimi R :: silt {});
}

Kui teil on keerukamad reeglid, peate siiski vajama võimsamat lahendust - SFINAE:

C ++ 14:

struct BazTag: FooTag, BarTag {};
mall  :: väärtus &&
 on  :: väärtuse is_baas
> korda (L l, R r) {
 tagastamise foldFB (l, r);
}

C ++ 17-ga saate kirjeldada neid reegleid väiksema katlaga ja selgemalt:

mall 
automaatne voltimine (L l, R r) {
 kasutades lTag = tüübinimi L :: silt;
 kasutades rTag = tüübinimi R :: silt;
kui constexpr (is_base_of  :: väärtus) {
 kui constexpr (is_same  :: väärtus) {
   tagastamise foldFB (l, r);
 } veel {
   tagastamise kordBB (l, r);
 } veel {
   tagasi foldFF ();
 }
}

See on väga praktiline, kuna if-idega töötamine on intuitiivsem kui mitmesuguste keelefunktsioonide kasutamine.

Metafunktsioonide taastamine muutub sama lihtsaks kui tavaline kood. If-constexpri puhul on mitmetähenduslike ülekoormuste ja muude ootamatute komplikatsioonide pärast muretsemine minevik.

Uuendame oma kompilaatorit kohe, kui Clang 3.9 on stabiilne.