Back
Close

7 Features of C++17 that will simplify your code

fenbf
585.5K views

constexpr if

This is a big one!

The static-if for C++!

The feature allows you to discard branches of an if statement at compile-time based on a constant expression condition.

if constexpr(cond)
     statement1; // Discarded if cond is false
else
     statement2; // Discarded if cond is true

For example:

template <typename T>
auto get_value(T t) {
    if constexpr (std::is_pointer_v<T>)
        return *t;
    else
        return t;
}
constexpr if simple example

Regarding more code samples? Hmm... constexpr if can be used to replace several tricks that were already done:

  • SFINAE technique to remove not matching function overrides from the overload set
  • you might want to look at places with C++14's std::enable_if - that should be easily replaced by constexpr if.
  • Tag dispatch

So, in most of the cases, we can now just write a constexpr if statement and that will yield much cleaner code. This is especially important for metaprogramming/template code that is, I think, complex by its nature.

A simple example: Fibonacci:

template<int  N>
constexpr int fibonacci() {return fibonacci<N-1>() + fibonacci<N-2>(); }
template<>
constexpr int fibonacci<1>() { return 1; }
template<>
constexpr int fibonacci<0>() { return 0; }

Now, it can be written almost in a 'normal' (no compile time version):

template<int N>
constexpr int fibonacci()
{
    if constexpr (N>=2)
        return fibonacci<N-1>() + fibonacci<N-2>();
    else
        return N;
}

In C++ Weekly episode 18 Jason Turner makes an example that shows that constexpr if won't do any short circuit logic, so the whole expression must compile:

if constexpr (std::is_integral<T>::value && 
              std::numeric_limits<T>::min() < 10)
{

}

For T that is std::string you'll get a compile error because numeric_limits are not defined for strings.

In the C++Now 2017: Bryce Lelbach “C++17 Features"/16th minute there's a nice example, where constexpr if can be used to define get<N> function - that could work for structured bindings.

struct S 
{
    int n;
    std::string s;
    float d;
};

template <std::size_t I>
auto& get(S& s)
{
    if constexpr (I == 0)
        return s.n;
    else if constexpr (I == 1)
        return s.s;
    else if constexpr (I == 2)
        return s.d;
}

Versus previously you would have needed to write:

template <> auto& get<0>(S &s) { return s.n; }
template <> auto& get<1>(S &s) { return s.s; }
template <> auto& get<2>(S &s) { return s.d; }
constexpr if get for structures

As you can see it's questionable which is the simpler code here. Although in this case, we've used only a simple struct, with some real world examples the final code would be much more complex and thus constexpr if would be cleaner.

More details:

MSVC 2017.3, GCC: 7.0, Clang: 3.9.

Create your playground on Tech.io
This playground was created on Tech.io, our hands-on, knowledge-sharing platform for developers.
Go to tech.io