c++ templates c++11 language-lawyer

c++ - ¿Por qué el ID de plantilla en "A<0>=0" no se compila sin espacio debido al operador mayor o igual que ">="?



templates c++11 (1)

template <int> using A = int; void f(A<0>=0); // Attempting to declare a function f taking int, // with the default argument 0 // Works as expected: // void f(A<0> = 0);

Esto tampoco compila en GCC 4.9.2 ni en Clang 3.5, y mucho menos en ICC o VC ++. Aparentemente el >= bit se analiza como un operador mayor o igual que. Sin embargo, esto parece ser incorrecto con respecto a [temp.names] / 3:

Después de la búsqueda de nombres (3.4) encuentra que un nombre es un nombre de plantilla o que un id de función de operador o un operador literal se refiere a un conjunto de funciones sobrecargadas cuyo miembro es una plantilla de función, si esto se sigue con < , < siempre se toma como el delimitador de una plantilla-argumento-lista y nunca como el operador menor que. Al analizar una plantilla-argumento-lista , el primer > 138 no anidado se toma como el delimitador final en lugar de como un operador mayor que. [..] [ Ejemplo:

template<int i> class X { /* ...*/ }; X< 1>2 > x1; // syntax error X<(1>2)> x2; // OK

- ejemplo final ]

138) A > que incluye el ID de tipo de un dynamic_cast , static_cast , reinterpret_cast o const_cast , o que incluye los argumentos de la plantilla s de un template-id posterior, se considera anidado a los fines de esta descripción.

¿Me estoy perdiendo algo o es esto un error del compilador?


Este es un efecto del principio máximo de munch , que hace que el analizador léxico tome tantos caracteres como sea posible para formar un token válido. Esto está cubierto en el borrador de la sección estándar de C ++ 2.5 [lex.pptoken] que dice:

De lo contrario, el siguiente token de preprocesamiento es la secuencia más larga de caracteres que podría constituir un token de preprocesamiento, incluso si eso hiciera fallar el análisis léxico adicional.

Cualquier caso como el que cita arriba necesita una excepción específica tal como este caso para <:: , podemos ver un ejemplo en el siguiente código:

template<typename T> class SomeClass; class Class; SomeClass<::Class>* cls;

que se trata en esta pregunta , la excepción se enumera en la viñeta que se encuentra justo encima de la regla de consumo máximo:

De lo contrario, si los siguientes tres caracteres son <:: y el carácter siguiente no es ni: ni>, <se trata como un token de preprocesador por sí mismo y no como el primer carácter del token alternativo <:.

y, por supuesto, el que no anidado > que cites en tu pregunta.

Tenga en cuenta que podemos ver que >= es un token de preprocesador de la sección 2.13 [lex.operators] que dice:

La representación léxica de los programas C ++ incluye varios tokens de preprocesamiento que se utilizan en la sintaxis del preprocesador o se convierten en tokens para operadores y puntuadores:

e incluye >= en la lista.

La >> corrección

Podemos ver en la propuesta que fijó el >> caso: N1757 que dice ( énfasis mío ):

Desde la introducción de los corchetes angulares, los programadores de C ++ se han sorprendido por el hecho de que dos corchetes angulares rectos consecutivos deben estar separados por espacios en blanco:

#include <vector> typedef std::vector<std::vector<int> > Table; // OK typedef std::vector<std::vector<bool>> Flags; // Error

El problema es una consecuencia inmediata del principio de "máxima mordida" y del hecho de que >> es un token válido (desplazamiento a la derecha) en C ++.

Este problema es un problema menor, pero persistente, molesto y algo embarazoso. Si el costo es razonable, parece que vale la pena eliminar la sorpresa.

El propósito de este documento es explicar formas de permitir que >> se trate como dos corchetes angulares de cierre, así como para analizar los problemas resultantes. Se propone una opción específica junto con una redacción que implementaría la propuesta en el documento de trabajo actual.

También señala el caso >=

También vale la pena señalar que el problema también puede ocurrir con los tokens >> = y> = . Por ejemplo

void func(List<B>= default_val1); void func(List<List<B>>= default_val2);

Ambas formas están actualmente mal formadas. Puede ser conveniente abordar también este problema, pero este documento no tiene la intención de hacerlo.

Tenga en cuenta que este cambio rompió la compatibilidad con C ++ 03 .