Ambigüedad de la plantilla de C++
Pregunta
Un amigo y yo estábamos hablando de plantillas de C++.Me preguntó qué debería hacer esto:
#include <iostream>
template <bool>
struct A {
A(bool) { std::cout << "bool\n"; }
A(void*) { std::cout << "void*\n"; }
};
int main() {
A<true> *d = 0;
const int b = 2;
const int c = 1;
new A< b > (c) > (d);
}
La última línea de main tiene dos análisis razonables.¿Es 'b' el argumento de la plantilla o es b > (c)
el argumento de la plantilla?
Aunque es trivial compilar esto y ver qué obtenemos, nos preguntamos qué resuelve la ambigüedad.
Solución
AFAIK se compilaría como new A<b>(c) > d
.Esta es la única forma razonable de analizarlo en mi humilde opinión.Si el analizador no puede asumir en circunstancias normales un argumento > final de una plantilla, eso resultaría en mucha más ambigüedad.Si lo quieres al revés, deberías haber escrito:
new A<(b > c)>(d);
Otros consejos
Como indica Leon & Lee, 14.2/3 (C++ '03) define explícitamente este comportamiento.
C++ '0x aumenta la diversión con una regla similar que se aplica a >>
.El concepto básico es que al analizar una lista de argumentos de plantilla, una lista de argumentos no anidada >>
serán tratados como dos distintos >
>
tokens y no el operador de turno correcto:
template <bool>
struct A {
A(bool);
A(void*);
};
template <typename T>
class C
{
public:
C (int);
};
int main() {
A<true> *d = 0;
const int b = 2;
const int c = 1;
new C <A< b >> (c) > (d); // #1
new C <A< b > > (c) > (d); // #2
}
'#1' y '#2' son equivalentes en lo anterior.
Por supuesto, esto soluciona la molestia de tener que agregar espacios en especializaciones anidadas:
C<A<false>> c; // Parse error in C++ '98, '03 due to "right shift operator"
El estándar C++ define que si para un nombre de plantilla seguido de un <
, el <
es siempre el comienzo de la lista de argumentos de la plantilla y el primer no anidado >
se toma como el final de la lista de argumentos de la plantilla.
Si pretendía que el resultado de la >
operador sea el argumento de la plantilla, entonces deberá encerrar la expresión entre paréntesis.No necesitas paréntesis si el argumento era parte de un static_cast<>
u otra expresión de plantilla.
La avidez del léxer es probablemente el factor determinante a falta de paréntesis para hacerlo explícito.Supongo que el Lexer no es codicioso.