2009-10-20 5 views
9

Aquí hay algo que observé en varios compiladores. Parece que hay errores de compilación.¿Por qué el manejo de expresiones de parámetros de plantillas sin tipo es inconsistente en los compiladores?

template <int I> 
struct X 
{ }; 

int main(void) 
{ 
    X<(16 > 1)> a;  // Works on vc9, works on g++ 4.1.2, works on Comeau 4.3.10.1 
    X<(int(16) > 1)> b; // Works on vc9, works on g++ 4.1.2, works on Comeau 4.3.10.1 
    X<(16 >> 1)> c;  // Works on vc9, works on g++ 4.1.2, works on Comeau 4.3.10.1 
    X<(int(16) >> 1)> d; // Fails on vc9, works on g++ 4.1.2, works on Comeau 4.3.10.1 

    X<16 > 1> e;   // Fails on vc9, works on g++ 4.1.2, fails on Comeau 4.3.10.1 
    X<int(16) > 1> f; // Fails on vc9, fails on g++ 4.1.2, fails on Comeau 4.3.10.1 
    X<16 >> 1> g;  // Fails on vc9, works on g++ 4.1.2, fails on Comeau 4.3.10.1 
    X<int(16) >> 1> h; // Fails on vc9, works on g++ 4.1.2, fails on Comeau 4.3.10.1 
} 

¿Por qué esa inconsistencia? ¿Qué está permitido/no permitido por el estándar? Tal comportamiento también es responsable del error de sintaxis al usar BOOST_AUTO en vc9. Me parece que Comeau está haciendo el trabajo correcto al rechazar todas las expresiones sin paréntesis.

+5

no creo que tenga nada que ver con la plantilla no ser de tipo, sino más bien porque usa el caracter '>' dentro de la plantilla. – Marcin

+0

Tiene razón, Marcin, he visto este comportamiento incoherente con operadores ">" y ">>" sobrecargados de clases definidas por el usuario. – Sumant

+2

Porque sería una construcción poco utilizada y, por lo tanto, menos probada. Y de todos modos estarías loco por usarlos en código real. Pero vale la pena presentar estos como pruebas al fabricante del compilador para que puedan agregarlo a su serie de pruebas de locos que hacen las personas. –

Respuesta

8

Las reglas son como sigue para C++ 03:

Después de búsqueda de nombre (3.4) encuentra que un nombre es un nombre de la plantilla, si este nombre es seguido por un <, la < es siempre tomado como el comienzo de una plantilla-argumento-lista y nunca como un nombre seguido por el operador menor que. Al analizar un ID de plantilla, el primer > no anidado [nota de pie: A > que incluye el ID de tipo de dynamic_cast, static_cast, reinterpret_cast o const_cast, o que incluye los argumentos de plantilla de una plantilla-id posterior, se considera anidado a los fines de esta descripción. ] se toma como el final de la plantilla-argumento-lista en lugar de un operador mayor que.

Así, el resultado es:

X<(16 > 1)> a;  // works 
    X<(int(16) > 1)> b; // works 
    X<(16 >> 1)> c;  // works 
    X<(int(16) >> 1)> d; // works 

    X<16 > 1> e;   // fails 
    X<int(16) > 1> f; // fails 
    X<16 >> 1> g;  // works (">>" is not a ">" token) 
    X<int(16) >> 1> h; // works (">>" is not a ">" token). 

Sin embargo, en C++ 0x las siguientes son las reglas

Después nds búsqueda de nombre (3.4) fi que un nombre es un plantilla- name, o que un id. de función del operador se refiere a un conjunto de funciones sobrecargadas cuyo miembro es una plantilla de función, si esto es seguido por un <, el < siempre se toma como el delimitador de una plantilla-argumento-lista y nunca como menos que ope o. Al analizar una plantilla-argumento-lista, la primera no anidada> [nota de pie: A > que incluye el ID de tipo de dynamic_cast, static_cast, reinterpret_cast o const_cast, o que incluye los argumentos de plantilla de una plantilla posterior- id, se considera anidado a los fines de esta descripción.] se toma como el delimitador final en lugar de un operador mayor que. De manera similar, el primer >> no anidado se trata como dos tokens > consecutivos pero distintos, el primero de los cuales se toma como el final de la plantilla-argumento-lista y completa el id-plantilla.

resultado será

X<(16 > 1)> a;  // works 
    X<(int(16) > 1)> b; // works 
    X<(16 >> 1)> c;  // works 
    X<(int(16) >> 1)> d; // works 

    X<16 > 1> e;   // fails 
    X<int(16) > 1> f; // fails 
    X<16 >> 1> g;  // fails (">>" translated to "> >") 
    X<int(16) >> 1> h; // fails (">>" translated to "> >") 

asegúrese de desactivar C++ 0x el modo en comeau al probar

+0

¡Excelente respuesta! En Comeau, con C++ 0x desactivado, el resultado es el descrito anteriormente (6 trabajos, 2 errores). – Sumant

+0

Siempre puedes contar con litb para hacer la investigación también :) – Marcin

2

De acuerdo con Stroustrup: "El primer elemento no anidado> termina una lista de argumentos de plantilla. Si se necesita más de lo necesario, se deben usar paréntesis".

Por lo tanto, los compiladores que toleran el segundo conjunto de expresiones lo hacen incorrectamente; el compilador que falla en X<(int(16) >> 1)> d; tiene errores.

+1

eso significaría que los compiladores que fallan en X <16 >> 1> también tienen errores, ya que >> no son dos> (molestia de plantilla anidada famosa) – falstro

Cuestiones relacionadas