This compiles
void f() {
constexpr bool x{};
auto g = []{
if constexpr (x) {
}
};
g();
}
int main () {
f();
}
and it compiles even if I change []
to [x]
or to [&x]
. In these two latter cases, though, clangd tells me
Lambda capture 'x' is not required to be captured for this use (fix available) [-Wunused-lambda-capture]
A first minor question would be: is capturing x
in this case simply redundant? Or there's more?
But my main question is: from where in the standard should I understand that I can make without any capture in the case above? After all, just writing (void)x;
before the if constexpr
, for instance, makes the capture ([x]
or [&x]
) necessary.
CodePudding user response:
A variable is required to be captured if it is a local entity that is odr-used within the lambda expression. See [basic.def.odr]/10. In your example, x
is a local entity but it is not odr-used by if constexpr (x)
because:
x
is a variable of non-reference type that is usable in constant expressions and has no mutable subobjects, and- the lvalue-to-rvalue conversion is applied immediately.
See [basic.def.odr]/5.2. (In a limited set of situations, the lvalue-to-rvalue conversion is allowed to not be done immediately; see [basic.def.odr]/3.)
In general, [basic.def.odr]/5 is the place to look when you need to determine whether a variable is odr-used.
CodePudding user response:
The case is ODR-usage (or rather: non-ODR-usage in this particular case) and it's not C 20-specific.
See expr.prim.lambda.capture
If an expression potentially references a local entity within a declarative region in which it is odr-usable, and the expression would be potentially evaluated if the effect of any enclosing typeid expressions (7.6.1.7) were ignored, the entity is said to be implicitly captured by each intervening lambda-expression with an associated capture-default that does not explicitly capture it.
Taking a look into the examples and notes that follow may also be worthwhile:
Note: The set of captured entities is determined syntactically, and entities might be implicitly captured even if the expression denoting a local entity is within a discarded statement (8.5.1). Example:
template<bool B>
void f(int n) {
[=](auto a) {
if constexpr (B && sizeof(a) > 4) {
(void)n; // captures n regardless of the value of B and sizeof(int)
}
}(0);
}
In previous standards it was more clearly stated imho, see: https://stackoverflow.com/a/42611583/4885321