if constexpr
is a bit confusing in this regard.
It's not there to ensure that unreachable branches are optimised out (that usually happens anyway).
It's there to allow us to write code that may not compile without breaking the build if the compilation error depends on a template parameter. It's all about template instantiation.
So:
template <typename T>
void foo(T x)
{
if constexpr (std::is_same_v<T, int>)
{
// Code that's semantically invalid for non-int can go here!
// Naive example (though obviously this works with some non-int types too)
x += 42;
}
}
Unfortunately this does not extend to a condition that doesn't depend on T, so if you wanted to do this:
constexpr bool DoThings = false;
void foo()
{
if constexpr (DoThings)
{
static_assert(false);
}
}
… the assertion will still fire; your program is ill-formed. It's not necessarily easy to come up with a real-world example of when you'd get hit by this, but it's still arguably unexpected.
In general, try not to think of constexpr
as having anything to do with "optimisation". It's about build phases; it is a tool that sometimes let you enforce some things "happening" in the realm of the template metahackerer. In practice, this generally implies compile-time execution, but it's not directly related to "optimising things out", and you shouldn't start sprinkling if constexpr
everywhere just to try to remove "dead" branches from your compiled executable: your compiler is doing that anyway (and why do you have dead branches in your code?).