Why in this example the first call doesn't compile and the second one compiles?
consteval auto foo(auto x) {
static_assert(x);
}
int main(){
foo(42); // error: non-constant condition for static assertion
foo([]{}); // OK
}
If I understand correctly, the first one is wrong due to lvalue-to-rvalue conversion not being a constant expression. Why then the second one is OK?
CodePudding user response:
static_assert(x);
while passing []{}
works, because a capture-less lambda has a conversion operator to function pointer and a function pointer can be converted to a bool
(which is going to be true
for everything but a null pointer which the conversion can't return).
An expression is a core constant expression as long as it doesn't fall in any of a number of exceptions listed in [expr.const]/5. In relation to the potentially relevant exceptions, neither is x
a reference, which would disqualify the expression x
from being a constant expression immediately, nor is a lvalue-to-rvalue conversion on x
or one of its subobjects required in the call to the conversion function or the conversion to bool
. The returned function pointer is in no way dependent on the value of the lambda. The call to the conversion function is also allowed in a constant expression, since it is specified to be constexpr
([expr.prim.lambda.closure]/11), so that the exception of calling a non-constexpr
function also doesn't apply.
None of the exceptions apply and x
(including the conversions to bool
) is a constant expression. The same is not true if 42
is passed, because the conversion to bool
includes an lvalue-to-rvalue conversion on x
itself.