44 votes

Pourquoi les const ints (ou shorts) sont-ils capturés implicitement dans lambdas?

Cela compile:

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

Mais ça:

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

produit:

"erreur: 'x' n'est pas capturé"

Pourquoi?

Je l'ai testé à la fois sur GCC (différentes versions de 5.0.0 à 8.0.0) et sur Clang (différentes versions de 4.0.0 à 6.0.0). Il se comporte de la même manière dans tous les cas.

38voto

gsamaras Points 9567

Lambda est portée de manière implicite par la capture de variables au sein d'atteindre la portée.

Vos variables sont dans l'atteinte portée, car ils sont locales à la (principale) de la fonction qui définit le lambda.

Cependant, il ya certains critères dans les variables qui peuvent être capturés par le biais de ce mécanisme, comme mentionné dans [expr.prim.lambda]/12:

Une lambda-expression associée à une capture par défaut qui n'a pas explicitement cette capture ou une variable avec stockage automatiquede la durée [..], il est dit à implicitement, la capture de l'entité (c'est à dire, ce ou une variable) si le composé déclaration:

-odr-usages ([base.def.odr]) l'entité, ou

-les noms de l'entité à une possible évaluation de l'expression ([base.def.odr]) où la enfermant pleine expression dépend d'un générique paramètre lambda déclarée au sein de l'atteindre champ d'application de la la lambda-expression.

La partie la plus importante est dans [expr.const]/2.7:

Un conditionnel expression e est une base constante de l'expression , à moins que le l'évaluation de l' e, [..] permettrait d'évaluer l'une des expressions suivantes:

une lvalue-à-rvalue de conversion ([conv.lval]) sauf si elle est appliquée à:

un non-volatile glvalue de l' intégrale ou une énumération de type qui fait référence à un non-volatile const objet avec un précédent initialisation, initialisé avec une expression constante.

Donc, const int est une base constante de l'expression tout en const float ne l'est pas.

En outre [expr.const]1826 mentionne:

Const integer initialisé avec une constante peut être utilisé dans des expressions constantes, mais const virgule flottante variable initialisée avec une constante ne peut pas.

Lire la suite dans Pourquoi est une variable const parfois pas besoin d'être capturé dans un lambda?

9voto

Rxmsc Points 927

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

Une lambda-expression associée à une capture par défaut qui n'a pas explicitement cette capture ou une variable automatique de la durée de stockage (ce qui exclut toute id-expression qui a été trouvé à se référer à une init-capture associés non-membre de données statiques), est dit implicitement, la capture de l'entité (c'est à dire, ce ou une variable) si le composé déclaration:

odr-usages (3.2) l'entité, ou

les noms de l'entité dans une potentiellement évaluation de l'expression (3.2) où l' joignant la pleine expression dépend d'un générique de paramètre lambda déclarés dans le large spectre de la lambda-expression.

Aussi, .open-std.org :

Const integer initialisé avec une constante peut être utilisée en constante expressions, mais const virgule flottante variable initialisée avec un constant ne peut pas. C'était intentionnel, pour être compatible avec le C++03 tout en encourageant l'utilisation constante de la constexpr. Certaines personnes ont trouvé cette distinction étonnant, cependant.

Il a également été observé qu'en permettant const variables à virgule flottante, comme des expressions constantes serait un ABI-modification de rupture, car il serait affecter lambda de capture.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X