This question is related to my previous question Compiler error when trying to call template method from private instance, which was pointed out to be related to this question: Where and why do I have to put the "template" and "typename" keywords?
So I read this and I get the idea that the C++ language definition is ambiguous so it cannot always be parsed correctly. In my case, the answer was that I need a.template f<1>() in B::test() to help the parser understand that it is dealing with a template. Fine.
But, after reading all this, why the heck is the parser suddenly able to do without the template keyword if I happen to have a completely unrelated global template function that happens to have the same name? This compiles without problems and behaves as expected:
#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();
}
I found that the global function must:
- be called 
f - be a template function
 - be defined before 
B 
Otherwise, it can be pretty much anything. So
template <typename T, unsigned k>
void *f(double x, const char *s) {return NULL;}
works just as well to help the parser out that a.f<1>() in B::test() is in fact to be parsed as a.template f<1>().
What is the compiler thinking? Like: "Well, the guy already has a global template function called f<>(), so when I'm parsing this completely unrelated expression a.f<1>() inside B::test(), I'm going to assume that it's also a template function?" What is this?
What did I miss when reading Where and why do I have to put the "template" and "typename" keywords??
Update
The code above compiles for me with all of:
- i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.9.00)
 - Apple clang version 3.1 (tags/Apple/clang-318.0.58) (based on LLVM 3.1svn)
 - g++-4.8 (GCC) 4.8.2
 
I also tested with the compiler flags -pedantic -Wall -Wextra and with -std=c++11 for g++-4.8. It worked in all cases.
Update 2
This also works without template keyword:
// ...
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();
}