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();
}