c++ language-lawyer extern auto

c++ - ¿Una declaración que usa "auto" coincide con una declaración externa que usa un especificador de tipo concreto?



language-lawyer (3)

Considere el siguiente programa:

extern int x; auto x = 42; int main() { }

Clang 3.5 lo acepta ( demostración en vivo ), GCC 4.9 y VS2013 no ( demostración en vivo para el primero ). ¿Quién tiene razón y dónde se especifica el comportamiento correcto en el Estándar de C ++?


Nota

Respondí una pregunta que se cerró un duplicado de esta. Pedí una combinación y en su lugar me dijeron que proporcionara una respuesta aquí . Vea a continuación mi respuesta original.

Actualizar clang es correcto

Hice esta pregunta en twitter y la respuesta que recibí de Richard Smith fue la siguiente:

No es un defecto, es intencional que esta restricción se aplique solo a los tipos de devolución deducidos y no a los tipos de variables . Para las variables, es solo una abreviatura de conveniencia, pero la deducción del tipo de retorno afecta algo más fundamental sobre las funciones (y especialmente las plantillas de funciones).

Entonces, la lógica es que esto está permitido por [dcl.spec.auto] y para restringir esto para los tipos de devolución deducidos [dcl.spec.auto]p11 se agregó [dcl.spec.auto]p11 lo contrario, no hay restricción y, por lo tanto, esto no está restringido para el caso de las variables.

Original

Actualmente [dcl.spec.auto] no parece cubrir este caso explícitamente, pero sí lo dice en [dcl.spec.auto]p5 :

Un programa que usa auto o decltype (auto) en un contexto que no está explícitamente permitido en esta subcláusula está mal formado.

y podemos ver que hace un caso similar para funciones mal formadas en [dcl.spec.auto]p11 :

Las redeclaraciones o especializaciones de una función o plantilla de función con un tipo de retorno declarado que usa un tipo de marcador de posición también usarán ese marcador de posición, no un tipo deducido . De manera similar, las redeclaraciones o especializaciones de una función o plantilla de función con un tipo de retorno declarado que no use un tipo de marcador de posición no deberán usar un marcador de posición . [Ejemplo:

auto f(); auto f() { return 42; } // return type is int auto f(); // OK int f(); // error, cannot be overloaded with auto f()

....

Por lo tanto, aunque esto podría servir de aclaración tal como está redactado en la actualidad, parece que gcc es correcto y está mal formado.


Hay sorprendentemente poco en el estándar sobre esto. Sobre todo lo que escuchamos sobre la redeclaración es:

[C++11: 3.1/1]: Una declaración (Cláusula 7) puede introducir uno o más nombres en una unidad de traducción o redeclarar nombres introducidos por declaraciones anteriores. [..]

y la única parte relevante de la semántica del auto :

[C++11: 7.1.6.4/3]: De lo contrario, el tipo de la variable se deduce de su inicializador. [..]

(Recordándonos que el tipo de x es int ).

Sabemos que una variable debe recibir el mismo tipo en todas las declaraciones:

[C++11: 3.5/10]: Después de todos los ajustes de tipos (durante los cuales las definiciones de tipo (7.1.3) se reemplazan por sus definiciones), los tipos especificados por todas las declaraciones que se refieren a una variable o función dada serán idénticos , excepto que las declaraciones para un objeto de matriz pueden especificar tipos de matriz que difieren por la presencia o ausencia de un límite de matriz principal (8.3.4). Una violación de esta regla en la identidad de tipo no requiere un diagnóstico.

y el "después de todos los ajustes de tipos" debería encargarse de cualquier pregunta relacionada con la participación del auto en todo esto; mi interpretación, entonces, es que esto es inherentemente una redeclaración válida (y definición) de la x en el ámbito global con el tipo int , y que Clang es correcto . Incluso si proponemos que auto no cuenta como "ajuste de tipo", ya que no se requiere ningún diagnóstico, en el peor de los casos, todas las implementaciones enumeradas son compatibles a su manera.

Creo que GCC y Visual Studio están tomando lo siguiente como inspiración:

[C++11: 7.1.6.4/5]: un programa que usa auto en un contexto no permitido explícitamente en esta sección está mal formado.

... pero creo que esto es miope. Parece improbable que el lenguaje estándar esté destinado a prohibir las reglas de redeclaración habituales, simplemente porque no se repiten o se hace referencia explícita desde 7.1.6.4 .

C ++ 14 agrega texto que se relaciona con declaraciones de funciones con tipos deducidos:

[C++14: 7.1.6.4/13]: redeclaraciones o especializaciones de una función o plantilla de función con un tipo de retorno declarado que usa un tipo de marcador de posición también usarán ese marcador de posición, no un tipo deducido. [..]

Por simetría, uno podría sugerir que, en su caso int , se pretende que GCC y VS sean correctos al rechazar el programa. Sin embargo, esta es una característica diferente (ya que la deducción no se puede aplicar a meras declaraciones) y por lo tanto un escenario diferente.

De cualquier manera, una redacción estándar mejorada ayudaría aquí. Lo considero un defecto editorial [razonablemente menor].


Me imagino que la restricción en [dcl.spec.auto]p11 existe porque de lo contrario, eso permitiría:

int f(); auto f(); // What''s the return type here?

La cosa es que puede tener un tipo de tipo sin deducir que tenga el tipo de retorno de una función. No hay reglas de deducción basadas en declaraciones anteriores, por lo que dicha mezcla no está permitida para las funciones, aunque lo siguiente sería perfectamente correcto:

int f(); auto f() { return 1; }

Este problema no existe para las variables:

extern int v; extern auto v; // ill-formed

Cualquier variable de solo declaración tiene que usar un tipo que no sea marcador de posición. Lo que esto significa es que si utiliza un tipo de marcador de posición para la definición de v , se puede deducir sin ningún problema y, por supuesto, tiene que coincidir con el tipo de marcador de posición no utilizado en la primera declaración.

extern int v; auto v = 1; // ok, type deduced as ''int'', matches first declaration.