Captura lambda y parámetro con el mismo nombre:¿quién hace sombra al otro? (clang vs gcc)

 C Programming >> Programación C >  >> Tags >> Clang
Captura lambda y parámetro con el mismo nombre:¿quién hace sombra al otro? (clang vs gcc)

Actualización:como prometió el presidente de Core en la cita inferior, el código ahora está mal formado:

Hubo algunos problemas relacionados con la búsqueda de nombres en lambdas hace un tiempo. Fueron resueltos por N2927:

La búsqueda siempre se realiza en el contexto de la expresión lambda , nunca "después" de la transformación al cuerpo de función miembro de un tipo de cierre. Ver [expr.prim.lambda]/8:

(El ejemplo también aclara que la búsqueda no considera de alguna manera el miembro de captura generado del tipo de cierre).

El nombre foo no se (re)declara en la captura; se declara en el bloque que encierra la expresión lambda. El parámetro foo se declara en un bloque anidado en ese bloque externo (consulte [basic.scope.block]/2, que también menciona explícitamente los parámetros lambda). El orden de búsqueda es claramente de bloques internos a externos. Por lo tanto, se debe seleccionar el parámetro, es decir, Clang es correcto.

Si tuviera que hacer la captura una captura inicial, es decir, foo = "" en lugar de foo , la respuesta no sería clara. Esto se debe a que la captura ahora induce una declaración cuyo "bloque" no se proporciona. Le envié un mensaje al presidente central sobre esto, quien respondió


Estoy tratando de agrupar algunos comentarios a la pregunta para darle una respuesta significativa.
En primer lugar, tenga en cuenta que:

  • Los miembros de datos no estáticos se declaran para la lambda para cada variable capturada por copia
  • En el caso específico, la lambda tiene un tipo de cierre que tiene un operador de llamada de función de plantilla en línea pública que acepta un parámetro llamado foo

Por lo tanto, la lógica me haría decir a primera vista que el parámetro debería sombrear la variable capturada como si estuviera en:

struct Lambda {
    template<typename T> void operator()(T foo) const { /* ... */ }
    private: decltype(outer_foo) foo{outer_foo};
};

De todos modos, @n.m. señaló correctamente que los miembros de datos no estáticos declarados para las variables capturadas por copia en realidad no tienen nombre. Dicho esto, todavía se accede al miembro de datos sin nombre por medio de un identificador (es decir, foo ). Por lo tanto, el nombre del parámetro del operador de llamada a la función todavía debería (permítanme decir) sombrear ese identificador .
Como señaló correctamente @n.m. en los comentarios a la pregunta:

Por eso, diría que el sonido metálico es correcto.