void f( int , const int (&)[2] = {}) { } // #1
void f( int , const int (&)[1] ) { } // #2
// void f(const int&, const int (&)[1] ) { } // #2_original
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
auto g2 = [ /* = */ ](auto a) {
int selector[ sizeof(a) == 1 ? 1 : 2 ]{};
f(x, selector); // OK: is a dependent expression, so captures x ???
};
}
This is an example from the C++14 Standard (ISO/IEC 14882:2014), Section 5.1.2, Paragraph 12, which I modified in 2 ways:
f()
have an int
as the first argument, so variable x
is not odr-used in any case.g2
.Is this code Standard-compliant? Both clang and gcc compile successfully. However, in the original example lambda g2
had a capture-default ([=]
), so variable x
was implicitly captured because there was a dependent expression (and also because it could be odr-used in function f() #2_original
). Note that in the aforementioned paragraph of the Standard there are 2 conditions to implicitly capture variable x
(odr-use OR dependent expression). Now, without capture-default nor odr-use:
Shouldn't this be a compile-time error since there is a dependent expression and no capture-default? That is, variable x
needs to be captured but it cannot be (assume g2
calls with both kinds of arguments, i.e., ones yielding sizeof(a)=1
and others sizeof(a)>1
).
Or does the condition of the dependent expression to implicitly capture a variable only apply when there is a capture-default? That would mean that, with no odr-use (i.e., without const int&
in function f() #2
) the program will work in the same way regardless of the capture-default. Therefore, wouldn't the second condition about the dependent expression be useless?
This is the C++14 Standard (ISO/IEC 14882:2014), Section 5.1.2, Paragraph 12 (emphasis mine):
A lambda-expression with an associated capture-default that does not explicitly capture this or a variable with automatic storage duration (this excludes any id-expression that has been found to refer to an init-capture’s associated non-static data member), is said to implicitly capture the entity (i.e., this or a variable) if the compound-statement:
- odr-uses (3.2) the entity, or
- names the entity in a potentially-evaluated expression (3.2) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
Note: lambda g
does not capture variable x
because it is not odr-used in f(x)
(see C++14 Standard (ISO/IEC 14882:2014), Section 5.1.2, Paragraph 13)
Links:
N3649: Generic (Polymorphic) Lambda Expressions (Revision 3)
Using of not captured variable in lambda
Is this code Standard-compliant?
Yes. The rule is:
If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses (3.2)
this
or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.
Does the lambda odr-use x
? No, because of [basic.def.odr]:
A variable
x
whose name appears as a potentially-evaluated expressionex
is odr-used byex
unless applying the lvalue-to-rvalue conversion (4.1) tox
yields a constant expression (5.20) that does not invoke any non-trivial functions and, ifx
is an object,ex
is an element of the set of potential results of an expressione
, where either the lvalue-to-rvalue conversion (4.1) is applied toe
, ore
is a discarded-value expression (Clause 5).
x
is an integral constant that is used in an expression where the lvalue-to-rvalue conversion is applied, so it is not odr-used. Since it's not odr-used, it's not an error that you aren't capturing it.
It would be ill-formed if there was an overload of f
that took its first argument by reference - that instantiation of the call operator would odr-use x
, but it's not captured, making it ill-formed.
The section you cite is irrelevant for your modified example. It only refers to "A lambda-expression with an associated capture-default". But your lambda doesn't have a capture-default. A capture-default is either =
or &
, the introducer []
has no capture-default. However, if we had [=]
or [&]
, that section would explain why x
would be captured.
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