meaning installed for c++ templates language-lawyer c++14 dependent-name

c++ - installed - llvm 3.7 0



static_assert depende del parĂ¡metro de plantilla que no sea de tipo(comportamiento diferente en gcc y clang) (2)

template <int answer> struct Hitchhiker { static_assert(sizeof(answer) != sizeof(answer), "Invalid answer"); }; template <> struct Hitchhiker<42> {};

Al intentar deshabilitar la static_assert instancias de plantilla general con static_assert , descubrí que el código anterior en clang genera el error de static_assert incluso cuando la plantilla no se instancia, mientras que gcc genera el error de afirmación solo cuando se instancia Hitchhiker con un parámetro distinto de 42 .

Jugueteando, encontré que esta afirmación:

template <int answer> struct Hitchhiker { static_assert(sizeof(int[answer]) != sizeof(int[answer]), "Invalid answer"); }; template <> struct Hitchhiker<42> {};

se comporta igual en ambos compiladores: la aserción solo se activa cuando se instancia la plantilla general.

¿Qué dice el estándar, qué compilador es el correcto?

g++ 4.9.2 clang++ 3.50


Ambos compiladores son correctos. Desde [temp.res] / 8:

Si no se puede generar una especialización válida para una plantilla, y esa plantilla no se instancia, la plantilla está mal formada, no se requiere diagnóstico.

No existe una especialización válida que pueda generarse a partir de la plantilla principal Hitchhiker , por lo que está mal formada, no se requiere diagnóstico. clang elige emitir un diagnóstico de todos modos.

Si solo desea permitir 42 , simplemente no defina la plantilla general:

template <int > struct Hitchhiker; template <> struct Hitchhiker<42> {};


Citas encontradas por @TartainLlama

Si una instancia hipotética de una plantilla inmediatamente después de su definición estaría mal formada debido a una construcción que no depende de un parámetro de plantilla, el programa está mal formado; No se requiere diagnóstico.

N4296 [temp.res] / 8

Esto se aplica inmediatamente después de definir la plantilla primaria (la que tiene el static_assert ). Por lo tanto, la especialización posterior (para 42 ) no se puede considerar, ya que aún no existe.

La siguiente pregunta es si static_assert( sizeof(answer) != sizeof(answer), depende de la answer . Semánticamente no lo hace, sintácticamente sí lo hace, y de manera estándar:

Dentro de una plantilla, algunas construcciones tienen una semántica que puede diferir de una instancia a otra. Tal construcción depende de los parámetros de la plantilla.

N4296 [temp.dep] / 1

La construcción sizeof(answer) != sizeof(answer) no difiere de una instanciación a otra. Por lo tanto, tal construcción no depende de los parámetros de la plantilla. Lo que significa que el static_assert completo no depende del parámetro de plantilla.

Por lo tanto, su programa está mal formado, no se requiere diagnóstico. Emitir un diagnóstico arbitrario (como el static_assert ) es un comportamiento válido del compilador. Falta el problema es el comportamiento válido del compilador. El comportamiento de un programa compilado a partir de un programa mal formado, no requiere diagnóstico, no está definido por el estándar: es un comportamiento indefinido. Los demonios nasales están permitidos.

Los intentos de fantasía (como sizeof(int[answer])!=sizeof(int[answer]) pueden complacer al compilador de Dios actual, pero no hacen que su programa esté mejor formado.

Podría presentar un caso en el que es poco probable que el compilador pueda atraparlo, pero la forma incorrecta sigue siendo independiente de la capacidad del compilador de atraparlo con él. Como regla general, C ++ quiere dejarse a sí mismo (y a sus compiladores) la libertad de encontrar código de plantilla inválido "antes de la instanciación"; Esto significa que el código de la plantilla debe producir posiblemente un código legal.

Es posible que desee algo como =delete con un mensaje adjunto.