I'm trying to understand if constexpr
fully.
I understand, that if if constexpr(expr)
used in a template, and expr
is dependent on a template parameter, then during instantiation, only one of the then
/else
branches will be instantiated, the other will be discarded.
I've got two questions:
expr
is not dependent on a template parameter, then no branches of if constexpr(expr)
will be discarded? If yes, where does the standard say so? I don't see where the standard has the exception that discard happens only when expr
is dependent.if constexpr
useful outside of templates? If yes, what are the use cases of this? Can you give some examples to understand its usefulness?Constexpr if If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
Short answer: static_assert(false) should never appear in a constexpr if expression, regardless of whether it's in a template function or whether it's in the discarded branch.
Is it true, that if
expr
is not dependent on a template parameter, then no branches ofif constexpr(expr)
will be discarded? If yes, where does the standard say so? […]
Yes, that is true. You're looking for [stmt.if]/2. Specifically this part:
[…] During the instantiation of an enclosing templated entity, if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated. […]
The best example I could find for a case where you would end up being value-dependent after instantiation is the one given by cppreference.com:
template<class T> void g() {
auto lm = [](auto p) {
if constexpr (sizeof(T) == 1 && sizeof p == 1) {
// this condition remains value-dependent after instantiation of g<T>
}
};
}
Is
if constexpr
useful outside of templates? If yes, can you give some examples to understand its usefulness?
While all branches will be instantiated when the if constexpr
does not appear inside of a template, [basic.def.odr]/10 still applies:
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; […]
emphasis mine. That effectively means that an odr-use of an entity in a discarded statement doesn't count. For example:
void blub();
constexpr bool use_blub = false;
void f()
{
if constexpr (use_blub)
{
blub();
}
}
The call to blub()
will not require that your program have a definition of blub()
if the condition is false. Using a normal if
, the program would still be required to provide a definition of blub()
somewhere, even if it is never used. So you could, e.g., use if constexpr
to toggle between calling some library function and calling some fallback implementation depending on whether the library is available (and being linked to). Apart from that, hypothetically, a compiler might not warn about unreachable code if it is unreachable due to an if constexpr
like it potentially would with a normal if
. I couldn't come up with an example of this using any actual compiler, however…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With