3

As shown in this question: link, if both of if branches are valid, there's no difference between:

const int foo = 5;
if (foo == 5)
{
    ...
}
else 
{
    ...
}

and

const int foo = 5;
if constexpr (foo == 5)
{
    ...
}
else 
{
    ...
}

in terms of optimization (in both cases the else branch would not be instantiated). So if the expression in vanilla if can be checked at compile time (it involves a const or constexpr) - the optimizations work here as well.

I previously thought that that was the purpose of if constexpr, but I am wrong. So is there a use case of if constexpr other than the case then we may have only one of many if branches valid?

dabljues
  • 1,663
  • 3
  • 14
  • 30

2 Answers2

7

A bit contrived example, but consider this:

const int foo = 6;
if (foo == 5)
{
    some_template_that_fails_to_compile_for_anything_else_than_5<foo>();
}

This will not compile even though the body of the if will never be executed! Still the compiler has to issue an error. On the other hand, this

const int foo = 6;
if constexpr (foo == 5)
{
    some_template_that_fails_to_compile_for_anything_else_than_5<foo>();
}

is fine, because the compiler knows at compile time the value of foo and hence does not bother about the body of the if.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
7

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?).

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055