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&nbsp;que toma un objeto de cualquier tipo y determina si su atributo foo es negativo. losmain&nbsp;la función crea una instanciafoo_negative&nbsp;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&nbsp;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&nbsp;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&nbsp;es una plantilla de miembro, entonces< 0&nbsp;es visto como pasar0&nbsp;como un argumento de plantilla, y hay una falta>, de ahí el error de sintaxis. Entonces cuandofoo_negative&nbsp;se crea una instancia con [T = X], hay otro error porqueX::foo&nbsp;no es una plantilla de miembro.

Pero porque piensav.foo&nbsp;es una plantilla de miembro? Esta ambigüedad es precisamente lo que eltemplate&nbsp;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&nbsp;¡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&nbsp;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.