He encontrado que al acceder a un atributo que no es de plantilla (v.foo
) desde una variable de un tipo de plantilla (T& v
), C++ puede engañarse haciéndole creer que es una plantilla de miembro si es una función de plantilla del mismo nombre (template class <T> void foo()
). ¿Cómo se puede explicar esto a partir de la especificación de C++? Considere este sencillo programa:C++ nombre de atributo confuso para la plantilla de miembro
#include <cassert>
/** Determine whether the 'foo' attribute of an object is negative. */
template <class T>
bool foo_negative(T& v)
{
return v.foo < 0;
}
struct X
{
int foo;
};
int main()
{
X x;
x.foo = 5;
assert(!foo_negative(x));
return 0;
}
Tenemos una función de plantilla foo_negative
que toma un objeto de cualquier tipo y determina si su atributo foo es negativo. La función main
crea instancias foo_negative
con [T = X]. Este programa se compila y se ejecuta sin ningún resultado.
Ahora, añadir esta función a la parte superior del programa:
template <class T>
void foo()
{
}
Compilarlo con G ++ 4.6.3 resultados en este error del compilador:
funcs.cpp: In function ‘bool foo_negative(T&)’:
funcs.cpp:13:14: error: parse error in template argument list
funcs.cpp: In function ‘bool foo_negative(T&) [with T = X]’:
funcs.cpp:25:5: instantiated from here
funcs.cpp:13:14: error: ‘foo’ is not a member template function
(donde la línea 13 es return v.foo < 0
y La línea 25 es assert(!foo_negative(x))
).
Clang produce errores similares.
Wat? ¿Cómo agregar una función no relacionada que nunca se llama administrar para introducir un error de sintaxis en un programa válido? Al analizar foo_negative
, el compilador no conoce el tipo de v
y, lo que es más importante, no sabe si v.foo
es una plantilla miembro o un miembro habitual. Aparentemente, debe decidir en el momento del análisis (antes de la instancia de la plantilla) si debe tratarlo como una plantilla de miembro o un miembro regular.
Si se piensa v.foo
es miembro de una plantilla, a continuación, < 0
se ve como pasa 0
como un argumento de plantilla, y hay una falta >
, de ahí el error de sintaxis. Luego, cuando foo_negative
se crea una instancia con [T = X], hay otro error porque X::foo
no es una plantilla de miembro.
¿Pero por qué cree que v.foo
es una plantilla de miembro? Esta ambigüedad es precisamente para lo que es la palabra clave template
: si escribí v.template foo
, le estaría diciendo explícitamente a C++ que esperara una plantilla de miembro, ¡pero no usé la palabra clave template
! No me referí a una plantilla de miembro, por lo que debe suponer que es un miembro regular. El hecho de que haya una función del mismo nombre que el miembro no debería tener ningún efecto. ¿Por qué? No puede ser un error en el compilador porque GCC y clang son consistentes.
eso es raro. Se compila en gcc-4.3.4: http://ideone.com/FP3SO –
No, olvidaste agregar la plantilla ' void foo()' declaration: http://ideone.com/FxEBm No compila . –
mgiuca
quizás sea realmente un error tanto en gcc como en clang: [declaración] (http://ideone.com/zofCF). Cambié 'v.foo < 0' to '0 > v.foo' y compila bien. Tal vez ambos compiladores piensan que '<0 'es un argumento de plantilla, como mencionaste en la pregunta. – user2k5