meaning compiler c++ declaration language-lawyer using-declaration

c++ - compiler - clang windows



Programa con encadenamiento de declaraciones de uso compiladas en MSVS y clang pero no en GCC (2)

Clang y MSVC son correctos; este código es válido Como señala Alf, [namespace.udecl] (7.3.3) / 10 dice

Una declaración de uso es una declaración y, por lo tanto, se puede usar repetidamente donde (y solo donde) se permiten declaraciones múltiples.

Sin embargo, no hay restricción en las declaraciones múltiples de la misma entidad en el ámbito del bloque, por lo que el ejemplo original es válido. Un caso correspondiente que no involucra el uso de la declaración s es:

int n; void f() { extern int n; extern int n; }

Esto es válido (y es aceptado por GCC, EDG, Clang y MSVC), por lo tanto (por la regla citada anteriormente) el ejemplo original también es válido.

Vale la pena señalar que el ejemplo en [namespace.udecl] (7.3.3) / 10 contiene un error. Dice:

namespace A { int i; } void f() { using A::i; using A::i; // error: double declaration }

... pero el comentario no es correcto; No hay error en la segunda declaración. Vea la discusión en el tema central 36 . He eliminado el ejemplo del estándar para que no confunda a más personas.

¿El siguiente programa está bien formado o mal formado de acuerdo con el estándar c ++?

namespace X { int i; } namespace Y { using X::i; } int main() { using X::i; using Y::i; }

Estoy obteniendo diferentes resultados con diferentes compiladores:

No quiero arreglar este programa para hacerlo compilar en GCC. Solo quiero saber qué dice el estándar de c ++ sobre esto y por qué los tres compiladores se comportan de manera diferente. También quiero que si este es el resultado de un error en cualquiera de estos compiladores.


El programa no debe compilarse porque declara X::i dos veces en el mismo ámbito de bloque.

C ++ 14 §7.3.3 / 10:

Una declaración de uso es una declaración y, por lo tanto, se puede usar repetidamente donde (y solo donde) se permiten declaraciones múltiples. [ Ejemplo:

namespace A { int i; } namespace A1 { using A::i; using A::i; // OK: double declaration } void f() { using A::i; using A::i; // error: double declaration }

Edit: El comentario no normativo citado anteriormente, y que pensé que respondía a la pregunta, estaba originalmente en C ++ 98 y sobrevivió a través del Corrigendum Técnico 1 (C ++ 03), C ++ 11 y C ++ 14. Pero al parecer está mal . Richard Smith en su respuesta cita el problema central 36 al respecto, el primero que lo planteó Andrew Koenig el 2 de agosto de 1998 (menos de un mes después de la aprobación de ANSI de la primera norma), lo que aparentemente significa que un comentario incorrecto conocido puede sobrevivir a tres revisiones de la estándar.

Citando el problema central en sí mismo sobre eso:

C ++ Cuestiones activas del lenguaje básico estándar, edición 36:

Notas de la reunión 04/00:
El grupo de trabajo de lenguaje central no pudo llegar a un consenso sobre qué tipo de declaración debería emular una declaración de uso . En una encuesta, 7 miembros se mostraron a favor de permitir declaraciones de uso dondequiera que pudiera aparecer una declaración de no definición, mientras que 4 prefirieron permitir múltiples explicaciones de uso solo en el ámbito del espacio de nombres (la razón es que el permiso para múltiples declaraciones de uso es principalmente para respaldar su uso en múltiples archivos de encabezado, que rara vez se incluyen en otro lugar que no sea el ámbito del espacio de nombres). John Spicer señaló que las declaraciones de friend pueden aparecer varias veces en el alcance de la clase y preguntó si las declaraciones de uso tendrían la misma propiedad bajo la resolución "como una declaración".

Como resultado de la falta de acuerdo, el problema se devolvió al estado "abierto".

La discusión general de las declaraciones múltiples del mismo nombre se encuentra en §3.3.1 / 4 tanto en C ++ 98 como en C ++ 14. Por lo que puedo ver, el texto de C ++ 14 es literalmente idéntico al texto original de C ++ 98. Y, por sí mismo, permite declarar el mismo nombre varias veces en la misma región declarativa en varios casos, uno de los cuales es que todas las declaraciones se refieren a la misma entidad:

C ++ 14 §3.3.1 / 4:

Dado un conjunto de declaraciones en una sola región declarativa, cada una de las cuales especifica el mismo nombre no calificado,

  • todos se referirán a la misma entidad, o todos se referirán a funciones y plantillas de funciones; o

  • exactamente una declaración declarará un nombre de clase o un nombre de enumeración que no sea un nombre typedef y las demás declaraciones se referirán a la misma variable o enumerador, o todas se referirán a funciones y plantillas de funciones; en este caso, el nombre de la clase o el nombre de la enumeración está oculto (3.3.10). [ Nota: Un nombre de espacio de nombres o un nombre de plantilla de clase debe ser único en su región declarativa (7.3.2, Cláusula 14). "Nota final "

Sin embargo, la redacción aquí solo dice lo que no es directamente inválido. Una declaración puede ser rechazada por otras reglas incluso si no es rechazada por esta. Por ejemplo, existe tal restricción para las declaraciones de miembros de clase:

C ++ 14 §9.2 / 1:

[…] Un miembro no se declarará dos veces en la especificación de miembro , excepto que una clase anidada o una plantilla de clase miembro se puede declarar y luego definir, y excepto que se puede introducir una enumeración con una declaración enumeración opaca y Más tarde redeclarado con un enum-specifier .

No encuentro una restricción de este tipo que admita el comentario aparentemente incorrecto en C ++ 14 §7.3.3 / 10 citado al inicio, es decir, no encuentro ningún tratamiento especial para los ámbitos de bloque o los espacios de espacio de nombres, por lo que es una conclusión tentativa. (teniendo en cuenta que la supervivencia del comentario, a pesar de haber sido impugnada ya en 1998), es que el comentario cuestionado en realidad es incorrecto y que el código de esta pregunta, donde dos declaraciones en la misma región declarativa se refieren a la misma entidad, es válido y debe aceptarse por todos los compiladores.