¿Por qué no se necesita una palabra clave de plantilla si existe una función de plantilla global no relacionada con el mismo nombre?

Esta pregunta está relacionada con mi pregunta anteriorError del compilador al intentar llamar al método de plantilla desde una instancia privada, que se señaló que estaba relacionado con esta pregunta:¿Dónde y por qué tengo que poner las palabras clave "plantilla" y "nombre de tipo"?

Entonces leí esto y tengo la idea de que la definición del lenguaje C ++ es ambigua, por lo que no siempre se puede analizar correctamente. En mi caso, la respuesta fue que necesitoa.template f<1>() enB::test() para ayudar al analizador a comprender que se trata de una plantilla. Multa.

Pero, después de leer todo esto, ¿por qué demonios es el analizador de repente capaz de prescindir deltemplate palabra clave si tengo una función de plantilla global completamente no relacionada que tiene el mismo nombre? Esto se compila sin problemas y se comporta como se esperaba:

#include <iostream>

template <int i>
void f() {std::cout << "f()\n";}

template <int N>
struct A {
    template <int i>
    void f() {std::cout << "A::f()\n";}
};

template <int N>
struct B {
    A<N> a;

    B(A<N>& a) : a(a) {}

    void test() {
        f<1>();
        a.f<1>();  // compiles without 'template' keyword!
    }
};

int main() {
    A<2> a;
    a.f<1>();   // works fine
    B<2> b(a);
    b.test();
}

Descubrí que la función global debe:

ser llamadofser una función de plantillaser definido antesB

De lo contrario, puede ser casi cualquier cosa. Entonces

template <typename T, unsigned k>
void *f(double x, const char *s) {return NULL;}

funciona igual de bien para ayudar al analizador de quea.f<1>() enB::test() es de hecho ser analizado comoa.template f<1>().

¿Qué está pensando el compilador? Como: "Bueno, el tipo ya tiene una función de plantilla global llamadaf<>(), así que cuando estoy analizando esta expresión completamente no relacionadaa.f<1>() dentroB::test(), Voy a suponer que también es una función de plantilla "¿Qué es esto?

¿Qué extrañé al leer?¿Dónde y por qué tengo que poner las palabras clave "plantilla" y "nombre de tipo"??

Actualizar

El código anterior se compila para mí con todos:

i686-apple-darwin11-llvm-g ++ - 4.2 (GCC) 4.2.1 (Basado en Apple Inc. compilación 5658) (LLVM compilación 2336.9.00)Apple clang versión 3.1 (etiquetas / Apple / clang-318.0.58) (basado en LLVM 3.1svn)g ++ - 4.8 (GCC) 4.8.2

También probé con las banderas del compilador-pedantic -Wall -Wextra y con-std=c++11 parag++-4.8. Funcionó en todos los casos.

Actualización 2

Esto también funciona sintemplate palabra clave:

// ...
template <int N, template <int> class A>
struct B {
    A<N> a;

    B(A<N>& a) : a(a) {}

    void test() {
        f<1>();
        a.f<1>();  // compiles without 'template' keyword!
    }
};

int main() {
    A<2> a;
    a.f<1>();   // works fine
    B<2, A> b(a);
    b.test();
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta