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:

template 
struct Arg {
 šablona 
 constexpr auto operator () (X x, Xs… xs) {
   return Arg  {} (xs…);
 }
};
šablona <>
struct Arg <0> {
 šablona 
 constexpr auto operator () (X x, Xs…) {
   návrat x;
 }
};
template 
constexpr auto arg = Arg  {};
// arg2 (0,1,2,3,4,5) == 2;

C ++ 17 to dělá trochu intuitivnější:

template 
struct 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:

šablona 
constexpr 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:

šablona 
auto compute (T x) -> decltype (enable_if_t  {}) {
 návrat x.Method ();
}
šablona 
auto compute (T x) -> decltype (enable_if_t  {}) {
 návrat 0;
}

C ++ 17:

šablona 
int 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;
};
šablona 
auto fold (Ll, Rr, FooTag, BarTag) {foldFB (l, r); }
/ * více dispečerských funkcí * /
šablona 
auto 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:

šablona 
auto 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.