7 Features of C++17 that will simplify your code
Open Source Your Knowledge, Become a Contributor
Technology knowledge has to be shared and made accessible for free. Join the movement.
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;
}
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; }
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:
- P0292R2
- Simon Brand: Simplifying templates and #ifdefs with if constexpr
- C++ Weekly Special Edition - Using C++17's constexpr if - YouTube - real examples from Jason and his projects.
- C++17: let’s have a look at the constexpr if – FJ - I've taken the idea of fibonacci example from there.
- C++ 17 vs. C++ 14 — if-constexpr – LoopPerfect – Medium - a lot of interesting examples
MSVC 2017.3, GCC: 7.0, Clang: 3.9.