versiones dev compiler c++ c++11

dev - C++ 11 static_assert y ejemplificación de plantilla



c++17 (6)

Creo que el compilador está en su derecho de expandir cualquier aserción estática que no dependa de los parámetros de la plantilla sin la necesidad de una instanciación, pero no creo que esto sea necesario. Recuerde también que los diferentes borradores de Estándares pueden tener diferentes reglas sobre cuándo esto puede ocurrir.

En C ++ 11, ¿la operación de static_assert dentro de una plantilla depende de si esa plantilla ha sido instanciada o no? Por ejemplo, con el siguiente código

template <int I> void sa() { static_assert(0,"Hello."); } int main(int argc, char *argv[]) { return 0; }

GCC 4.5.0 fallará la aserción y producirá el "Hola". mensaje. El compilador digital Mars versión 8.42n, por otro lado, no da ningún mensaje.


El borrador de C ++ 0x ( N3242 ) dice en 14.6p8:

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

Las mismas palabras aparecen en el estándar C ++ 03.

En el caso del ejemplo de la pregunta, no se puede crear una instancia válida para esta plantilla, por lo que se aplica la fraseología citada.

Como no se requiere diagnóstico, el compilador puede compilar el programa si la plantilla no se crea una instancia. Por supuesto, si se crea una instancia, entonces el programa está mal formado, con un diagnóstico requerido.


Esta es la sección 14.6.2 en C ++ estándar.

Su static_assert está relacionado con el soporte de nombres no dependientes vinculantes cuando se analiza inicialmente una plantilla . El Compilador de Marte Digital actualmente no es compatible con los nombres obligatorios no dependientes. GCC 4.5.0 admite nombres vinculantes no dependientes.

Si su expresión no depende de los parámetros de la plantilla, entonces se conoce dicha expresión cuando se analiza inicialmente una plantilla. El compilador debe mostrar el mensaje de error. GCC 4.5.0 lo hace.

Reemplace su 0 en static_assert con I*I < 0 , para la expansión y obtendrá el nombre dependiente. Aparecerá un mensaje de error solo para el caso de la plantilla desinstalada.


Este programa genera un error:

template <int I> void sa() { static_assert(0,"Hello."); } template <> void sa<0>() { } int main(int argc, char *argv[]) { return 0; }

Este programa no:

template <int I> void sa() { static_assert(I != 0,"Hello."); } template <> void sa<0>() { } int main(int argc, char *argv[]) { return 0; }

No tiene ningún sentido que este sea el caso. Así que llegué a la conclusión de que g ++ 4.5 debe estar en error si está activando el static_assert en una plantilla static_assert .

Y aún más problemático, el siguiente programa imprime I == 1 .

#include <iostream> using ::std::cout; template <int I> void sa() { cout << "I == " << I << ''/n''; static_assert(I != 0,"Hello."); } template <> void sa<0>() { cout << "I == " << 0 << ''/n''; } int main(int argc, char *argv[]) { sa<1>(); return 0; }

Esto indica que hay un error grave con la forma en que gcc maneja static_assert .

Editar : Oh, bueno. Mi programa tiene un error. Debería leer I == 0 , no I != 0 , y si eso ha cambiado, no compila como debería hacerlo.


GCC es correcto y el otro compilador también es correcto. Consulte 14.6p8 en la especificación

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

Por lo tanto, un compilador es libre de rechazar el siguiente

template<typename T> void f() { static_assert(0, "may trigger immediately!"); static_assert(sizeof(T) == 0, "may trigger immediately!"); }

Si quiere ir a salvo, debe organizarlo para que el compilador no pueda saber hasta la instanciación si la expresión booleana será verdadera o falsa. Por ejemplo, obtenga el valor de getvalue<T>::value , con getvalue como una plantilla de clase (podría especializarse, por lo que el compilador ya no puede conocer el valor booleano).


Usé una función auxiliar para hacer que el falso dependiera del parámetro de la plantilla:

template<typename T> bool dependentFalse<T>() { return false; } template<typename T> Foo foo() { static_assert(dependentFalse<T>(), "this template shouldn''t be instantiated"); }