Pour un lambda au bloc de portée, les variables répondant à certains critères dans le large spectre peut être utilisé de façon limitée à l'intérieur de la lambda, même s'ils ne sont pas capturés.
Grosso modo, pour atteindre la portée comprend toute variable locale à la fonction contenant le lambda, qui serait portée au point de la lambda a été défini. Donc, cela inclut m
et n
dans les exemples ci-dessus.
"À certains critères" et "limitée", sont spécifiquement (comme en C++14):
- À l'intérieur de la lambda, la variable ne doit pas être odr-utilisé, ce qui signifie qu'il ne doit pas subir toute opération, à l'exception:
- apparaissant comme un jeté de la valeur de l'expression (
m;
est l'un de ceux-ci), ou
- avoir sa valeur de récupération.
- La variable doit être:
- Un
const
, non-volatile
entier ou enum dont l'initialiseur était une expression constante, ou
- Un
constexpr
, non-volatile
variable (ou un sous-objet de ce genre)
Les références à C++14: [expr.const]/2.7, [de base.def.odr]/3 (première phrase), [expr.prim.lambda]/12, [expr.prim.lambda]/10.
La raison d'être de ces règles, comme suggéré par d'autres observations/réponses, c'est que le compilateur a besoin pour être en mesure de "synthétiser" un non-capture lambda comme une fonction indépendante du bloc (puisque de telles choses peuvent être convertis à un pointeur de fonction); il peut le faire en dépit de référence à la variable si elle sait que la variable aura toujours la même valeur, ou il peut répéter la procédure pour l'obtention de la valeur de la variable indépendante du contexte. Mais il ne peut pas le faire si la variable peut varier de temps à autre, ou si la variable adresse est nécessaire par exemple.
Dans votre code, n
a été initialisée par une non-expression constante. Par conséquent, n
ne peut pas être utilisé dans un lambda sans être capturé.
m
a été initialisée par une expression constante 42
, de sorte qu'il ne répondait pas à la "certains critères". Un jeté de la valeur de l'expression n'a pas d'odr-utiliser l'expression, alors m;
peuvent être utilisés sans l' m
d'être capturé. gcc est correct.
Je dirais que la différence entre les deux compilateurs, c'est que clang considère m;
d'odr-utiliser m
, mais gcc n'a pas. La première phrase de l' [de base.def.odr]/3 est assez compliqué:
Une variable x
dont le nom apparaît comme potentiellement-de l'expression évaluée ex
est odr-utilisée par ex
moins que l'application de la lvalue-à-rvalue conversion en x
donne une expression constante qui n'a pas invoquer la non-trivial fonctions et, si x
est un objet, ex
est un élément de l'ensemble des résultats possibles d'une expression e
, où la lvalue-à-rvalue de conversion est appliqué à l' e
ou e
est un jeté de la valeur de l'expression.
mais à la lecture de près, il fait spécifiquement mention qu'un rebut de la valeur de l'expression n'a pas d' odr-utilisation de l'expression.
C++11 de la version de [base.def.odr] à l'origine, n'incluent pas de la jetée de la valeur de l'expression, de ce bruit de comportement serait correct dans la publication de C++11. Cependant, le texte qui s'affiche en C++14 a été accepté comme un Défaut à l'encontre de C++11 (Numéro 712), de sorte que les compilateurs doivent mettre à jour leur comportement, même en C++11 mode.