C ++ 17 vs. C ++ 14 - if-constexpr
Jsme nadšeni, že if-constexpr se dostal do C ++ 17. Můžete si to vyzkoušet sami pomocí současného kmene drápů.
V tomto příspěvku na blogu jsme přehodnotili kód C ++ 14 a pokusili se použít novou funkci.
Nemáte-li k dispozici konstexpr, musíte se často uchýlit k propracování technik meta-programování, s využitím přizpůsobení vzorových vzorů, přetížení a SFINAE.
Příklad 1 - získání n-arg
Mnoho šablon meta-programů pracuje na seznamech typu variadic. V C ++ 14 je získání n-tého typu seznamů argumentů často implementováno následujícím způsobem:
templatestruct Arg { šablona constexpr auto operator () (X x, Xs… xs) { return Arg {} (xs…); } };
šablona <> struct Arg <0> { šablonaconstexpr auto operator () (X x, Xs…) { návrat x; } };
templateconstexpr auto arg = Arg {};
// arg2 (0,1,2,3,4,5) == 2;
C ++ 17 to dělá trochu intuitivnější:
templatestruct Get { šablona constexpr auto operator () (X x, Xs… xs) { pokud constexpr (n> velikost… (xs)) { vrátit se; } jinak, pokud constexpr (n> 0) { return Get {} (xs…); } jinde { návrat x; } } };
Příklad 2 - API - shimming
Někdy chcete podporovat alternativní API. C ++ 14 poskytuje snadný způsob, jak zkontrolovat, zda lze objekt určitým způsobem použít:
šablonaconstexpr auto podporujeAPI (T x) -> decltype (x.Method1 (), x.Method2 (), true_type {}) { vrátit se {}; }
constexpr auto podporujeAPI (…) -> false_type { vrátit se {}; }
Implementaci vlastního chování v C ++ 14 lze provést takto:
šablonaauto compute (T x) -> decltype (enable_if_t {}) { návrat x.Method (); }
šablonaauto compute (T x) -> decltype (enable_if_t {}) { návrat 0; }
C ++ 17:
šablonaint compute (T x) { pokud constexpr (podporujeAPI (T {})) { // bude kompilován, pouze pokud je podmínka pravdivá návrat x.Method (); } jinde { návrat 0; } }
To je velmi výhodné, protože kód, který sémanticky patří dohromady, není rozptýlen ve více funkcích. Dále můžete dokonce definovat lambda obsahující if-constexpr.
Příklad 3 - Výběr algoritmu kompilace
Často musíte najít nejlepší algoritmus založený na sadě pravidel a vlastností typu. Existuje mnoho řešení. Například STL používá TypeTags k výběru správného algoritmu pro některé dané iterátory.
struct FooTag {}; struct BarTag {};
auto foldFF (…) {} auto foldFB (…) {} auto foldBF (…) {} auto foldBB (…) {}
struct A { / *… * / using tag = FooTag; };
struct B { / *… * / using tag = BarTag; };
šablonaauto fold (Ll, Rr, FooTag, BarTag) {foldFB (l, r); } / * více dispečerských funkcí * /
šablonaauto fold (L l, R r) { vrácení záhybu (l, r, typename L :: tag {}, typename R :: tag {}); }
Jakmile však budete mít složitější pravidla, možná budete potřebovat výkonnější řešení - SFINAE:
C ++ 14:
struct BazTag: FooTag, BarTag {};
šablona:: value && is_base_of :: hodnota > fold (L l, R r) { návrat foldFB (l, r); }
S C ++ 17 můžete tato pravidla popsat s menším počtem varných desek a jasněji:
šablonaauto fold (L l, R r) { using lTag = typename L :: tag; using rTag = typename R :: tag;
if constexpr (is_base_of:: value) { if constexpr (is_same :: value) { návrat foldFB (l, r); } jinde { zpětný foldBB (l, r); } jinde { návrat foldFF (); } }
Je to velmi praktické, protože práce s ifs je intuitivnější než používání různých jazykových funkcí.
Refaktoring meta-funkcí je tak jednoduchý jako obyčejný kód. U if-constexpr je obava z nejasných přetížení a dalších neočekávaných komplikací minulostí.
Jakmile bude Clang 3.9 stabilní, upgradujeme náš kompilátor.