While working on this question, a possible answer implied nested lambdas where the inner ones implicitly captured a constexpr
local variable of the outer one. Here is a mre:
int main() {
[]() {
// must be declared static with msvc
constexpr int i = []() { return 42; }();
[]() { static_assert(i == 42); }();
}();
return 0;
}
LIVE
gcc and clang are fine with that but msvc issues error C3493: 'i' cannot be implicitly captured because no default capture mode has been specified
.
msvc only accepts the code if the variable is declared static
.
What compilers are right and why?
i
in i == 42
is not an odr-use per [basic.def.odr]/5.2.
Informally this is because in the expression you only use the value of i
, not its identity as an object, and because the variable is usable in constant expressions, i.e. its value is compile-time known (because the variable is declared constexpr
).
More specifically, you immediately apply a lvalue-to-rvalue conversion to i
for the built-in ==
operator which expects prvalue operands, as required for [basic.def.odr]/5.2 to apply. (It would be different if ==
resolved to an overloaded operator==
which takes arguments by-reference.)
Because there is no odr-use of i
, there is no need for it to be captured.