C ++ confuso nombre de atributo para la plantilla miembro

He encontrado que al acceder a un atributo sin plantilla (v.foo) a partir de una variable de un tipo de plantilla (T& v), Se puede engañar a C ++ para que piense que es una plantilla miembro si hay una función de plantilla con el mismo nombre (template class <T> void foo()). ¿Cómo se puede explicar esto a partir de la especificación de C ++? Considere este programa simple:

#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 plantillafoo_negative que toma un objeto de cualquier tipo y determina si su atributo foo es negativo. losmain la función crea una instanciafoo_negative con [T = X]. Este programa compila y ejecuta sin ningún tipo de salida.

Ahora, agregue esta función a la parte superior del programa:

template <class T>
void foo()
{
}

Compilarlo con G ++ 4.6.3 da como resultado 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 esreturn v.foo < 0 y la línea 25 esassert(!foo_negative(x)).)

Clang produce errores similares.

¿Wat? ¿Cómo agregar una función no relacionada que nunca se llama logró introducir un error de sintaxis en un programa válido? Cuando se analizafoo_negative, el compilador no sabe el tipo devY, sobre todo, no sabe si.v.foo es una plantilla de miembro o un miembro regular. Aparentemente, tiene que decidir en el momento del análisis (antes de que se cree una instancia de la plantilla) si se trata como una plantilla de miembro o un miembro regular.

Si piensav.foo es una plantilla de miembro, entonces< 0 es visto como pasar0 como un argumento de plantilla, y hay una falta>, de ahí el error de sintaxis. Entonces cuandofoo_negative se crea una instancia con [T = X], hay otro error porqueX::foo no es una plantilla de miembro.

Pero porque piensav.foo es una plantilla de miembro? Esta ambigüedad es precisamente lo que eltemplate palabra clave es para: si escribív.template foo, entonces le diría explícitamente a C ++ que espere una plantilla de miembro, pero no usé eltemplate ¡palabra clave! No me referí a una plantilla de miembro, por lo que debería suponer que es un miembro regular. El hecho de que hay unafunción del mismo nombre que el miembro no debería tener ningún efecto. ¿Por qué lo hace? No puede ser un error en el compilador porque GCC y clang son consistentes.

Respuestas a la pregunta(3)

Su respuesta a la pregunta