Why are const ints (or shorts) fixed implicitly in lambdas?

This compiles:

int main() { const int x = 123; auto g = []() { std::cout << x << "\n"; }; g(); } 

But this:

 int main(){ const float x = 123; auto g = []() { std::cout << x << "\n"; }; g(); } 

gives:

":" x "is not recorded"

Why?

I tested it both on GCC (various versions from 5.0.0 to 8.0.0) and on Clang (various versions from 4.0.0 to 6.0.0). He behaves the same in all cases.

+44
c ++ scope language-lawyer lambda one-definition-rule
Oct 13 '17 at 7:03 on
source share
2 answers

Lambda scope can implicitly capture variables within its scope.

Your variables are in scope since they are local to the (main) function that defines lambda.

However, there are certain criteria in which variables can be captured using this mechanism, as indicated in [expr.prim.lambda] / 12

An lambda expression with an associated default capture that does not explicitly commit this or a variable with an automatic storage duration of [..], says to implicitly capture an object (ie this or a variable ) if the connection operator:

-odr-uses ([basic.def.odr]) object or

- means an object in a potentially-evaluated expression ([basic.def.odr]), where the encompassing full expression depends on the general parameter lambda declared within the scope of the lambda expression .

The most important part is [expr.const] /2.7 :

conditional expression e is an expression of a constant constant , if only the estimate e , [..] evaluates one of the following expressions:

the lvalue-to-rvalue ([conv.lval]) conversion, if it does not apply to:

the unstable value of gl of an integral or type enumeration, which refers to a non-volatile const object with previous initialization, is initialized with a constant expression.

So const int is the main expression of the constant, but const float is not.

Moreover, [expr.const] 1826 mentions:

A conjugated integer initialized by a constant can be used in constant expressions, but a floating-point variable const, initialized by a constant, cannot.

More in detail. Why is the const variable sometimes not required to be written to lambda?

+37
Oct 13 '17 at 7:50
source share

C ++ 14 draft N4140 5.1.2.12 [expr.prim.lambda]:

An lambda expression with an associated default capture that does not explicitly commit this or a variable with automatic storage duration (this excludes any identification expression that has been found to refer to the init-capture associated with a non-static data element) is called to implicitly capture an object (i.e., this or a variable) if the connection operator:

odr uses (3.2) an object or

names the object in the potentially-evaluated expression (3.2), where the inclusion of the full expression depends on the general parameter of the lambda declared within the scope of the lambda expression.

In addition, .open-std.org :

A conjugate integer with a constant can be used in expression constants, but a floating-point variable const, an initialized constant, cannot. It was intentional to be compatible with C ++ 03 while encouraging consistent use of constexpr. Some people, however, this difference was surprising.

It has also been observed that accepting floating-point variables as constant expressions will be an ABI change, since it affects lambda capture.

+9
Oct 13 '17 at 8:37 on
source share



All Articles