c++ lambda scope language-lawyer one-definition-rule

c++ - ¿Por qué las estructuras(o los cortos) son capturados implícitamente en lambdas?



scope language-lawyer (2)

Esta pregunta ya tiene una respuesta aquí:

Esto compila:

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

Pero esto:

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

produce:

"error: ''x'' no se captura"

¿Por qué?

Lo probé tanto en GCC (varias versiones de 5.0.0 a 8.0.0) como en Clang (varias versiones de 4.0.0 a 6.0.0). Se comporta igual en todos los casos.


El alcance de Lambda puede capturar implícitamente variables dentro de su alcance.

Sus variables están en el alcance de alcance, ya que son locales a la función (principal) que define el lambda.

Sin embargo, hay ciertos criterios en los que las variables se pueden capturar a través de este mecanismo, como se menciona en [expr.prim.lambda]/12 :

Se dice que una expresión lambda con un valor predeterminado de captura asociado que no captura explícitamente esta o una variable con duración de almacenamiento automática [..], captura implícitamente la entidad (es decir, esta o una variable ) si la instrucción compuesta:

-odr-uses ([basic.def.odr]) la entidad, o

- nombra la entidad en una expresión potencialmente evaluada ([basic.def.odr]) donde la expresión completa adjunta depende de un parámetro lambda genérico declarado dentro del alcance de alcance de la expresión lambda .

La parte más importante es en [expr.const]/2.7 :

Una expresión condicional e es una expresión constante central a menos que la evaluación de e , [..] evalúe una de las siguientes expresiones:

una conversión de lvalue a rvalue ([conv.lval]) a menos que se aplique a:

un glvalue no volátil de tipo integral o de enumeración que se refiere a un objeto const no volátil con una inicialización precedente, inicializado con una expresión constante.

Así que const int es una expresión constante central mientras que const float no lo es.

Por otra parte [expr.const]1826 menciona:

Un entero const inicializado con una constante se puede usar en expresiones constantes, pero una variable de punto flotante const inicializado con una constante no puede .

Lea más en ¿Por qué una variable const no es requerida para ser capturada en una lambda?


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

Una expresión lambda con un valor predeterminado de captura asociado que no captura explícitamente esta o una variable con duración de almacenamiento automática (esto excluye cualquier expresión de id que se haya encontrado que se refiera a un miembro de datos no estático asociado a la captura init), es se dice que captura implícitamente la entidad (es decir, esta o una variable) si el enunciado compuesto:

odr-usa (3.2) la entidad , o

nombra la entidad en una expresión potencialmente evaluada (3.2) donde la expresión completa envolvente depende de un parámetro lambda genérico declarado dentro del alcance de alcance de la expresión lambda.

Además, [expr.const]1826 :

Un entero const inicializado con una constante se puede usar en expresiones constantes, pero una variable de punto flotante const inicializado con una constante no puede. Esto fue intencional, para ser compatible con C ++ 03 mientras se fomenta el uso consistente de constexpr. Sin embargo, algunas personas han encontrado esta distinción sorprendente.

También se observó que permitir las variables de coma flotante const como expresiones constantes sería un cambio de ruptura de ABI, ya que afectaría la captura de lambda.