C++ 17 vs. C++ 14 — if-constexpr

LoopPerfect
Jun 28, 2016 · 3 min read

We are excited to see that if-constexpr made it to C++ 17. You can try it yourself using the current trunk of clang.

In this blog-post we revisit some C++ 14 code and try to use the new feature.

Not having if-constexpr at your disposal, you often need to resort to elaborate meta-programming techniques, utilising template pattern-matching, overload-resolution and SFINAE.

Example 1 — getting the nth-arg

Many template meta-programs operate on variadic-type-lists. In C++ 14, getting the nth-type of an argument lists is often implemented the following way:

template<unsigned n>
struct Arg {
template<class X, class…Xs>
constexpr auto operator()(X x, Xs…xs) {
return Arg<n-1>{}(xs…);
}
};
template<>
struct Arg<0> {
template<class X, class…Xs>
constexpr auto operator()(X x, Xs…) {
return x;
}
};
template<unsigned n>
constexpr auto arg = Arg<n>{};
// arg<2>(0,1,2,3,4,5) == 2;

C++ 17 makes this slightly more intuitive:

template<unsigned n>
struct Get {
template<class X, class…Xs>
constexpr auto operator()(X x, Xs…xs) {
if constexpr(n > sizeof…(xs) ) {
return;
} else if constexpr(n > 0) {
return Get<n-1>{}(xs…);
} else {
return x;
}
}
};

Example 2 — API — shimming

Sometimes you want to support an alternative API. C++ 14 provides an easy way to check if an object can be used in a certain way:

template<class T>
constexpr auto supportsAPI(T x) -> decltype(x.Method1(), x.Method2(), true_type{}) {
return {};
}
constexpr auto supportsAPI(…) -> false_type {
return {};
}

Implementing custom behaviour in C++ 14 can be done like this:

template<class T>
auto compute(T x) -> decltype( enable_if_t< supportsAPI(T{}), int>{}) {
return x.Method();
}
template<class T>
auto compute(T x) -> decltype( enable_if_t<!supportsAPI(T{}), int>{}) {
return 0;
}

C++17:

template<class T>
int compute(T x) {
if constexpr( supportsAPI(T{}) ) {
// only gets compiled if the condition is true
return x.Method();
} else {
return 0;
}
}

This is very convenient as code that belongs semantically together is not scattered across multiple functions. Furthermore, you can even define lambdas containing if-constexpr.

Example 3 — Compile-time algorithm-picking

Often you need to find the best algorithm based on a set on rules and properties of a type. There are many solutions. For instance, the STL uses TypeTags to pick the right algorithm for some given iterators.

struct FooTag {};
struct BarTag {};
auto foldFF(…) {}
auto foldFB(…) {}
auto foldBF(…) {}
auto foldBB(…) {}
struct A {
/* … */
using tag = FooTag;
};
struct B {
/* … */
using tag = BarTag;
};
template<class L, class R>
auto fold(L l,R r, FooTag, BarTag) { foldFB(l,r); }
/* more dispatching functions*/
template<class L, class R>
auto fold(L l, R r) {
return fold(l,r,
typename L::tag{},
typename R::tag{} );
}

However, once you have more complex rules, you might need a more powerful solution — SFINAE:

C++ 14:

struct BazTag : FooTag, BarTag {};template<class L, class R,
enable_if_t<
is_same<L::tag, FooTag>::value &&
is_base_of<R::tag, BarTag>::value
> fold(L l, R r) {
return foldFB(l,r);
}

With C++ 17 you can describe these rules with less boilerplate and in a clearer way:

template<class L, class R>
auto fold(L l, R r) {
using lTag = typename L::tag;
using rTag = typename R::tag;
if constexpr( is_base_of<rTag, BarTag>::value ) {
if constexpr( is_same<lTag, FooTag>::value ) {
return foldFB(l,r);
} else {
return foldBB(l,r);
} else {
return foldFF();
}
}

This is very practical as working with ifs is more intuitive than using a variety of language-features.

Refactoring meta-functions becomes as simple as ordinary code. With if-constexpr, worrying about ambiguous overloads and other unexpected complications is a thing of the past.

We will upgrade our compiler as soon as Clang 3.9 is stable.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store