I’ve found that when accessing a non-template attribute (v.foo) from a variable of a template type (T& v), C++ can be tricked into thinking that it is a member template if there is a template function of the same name (template class <T> void foo()). How can this be explained from the C++ spec? Consider this simple program:
#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;
}
We have a template function foo_negative that takes an object of any type and determines whether its foo attribute is negative. The main function instantiates foo_negative with [T = X]. This program compiles and runs without any output.
Now, add this function to the top of the program:
template <class T>
void foo()
{
}
Compiling it with G++ 4.6.3 results in this compiler error:
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
(Where Line 13 is return v.foo < 0 and Line 25 is assert(!foo_negative(x)).)
Clang produces similar errors.
Wat? How did adding an unrelated function that is never called manage to introduce a syntax error into a valid program? When parsing foo_negative, the compiler doesn’t know the type of v, and crucially, it doesn’t know whether v.foo is a member template or a regular member. Apparently, it has to decide at parsing time (before the template is instantiated) whether to treat it as a member template or a regular member.
If it thinks v.foo is a member template, then < 0 is seen as passing 0 as a template argument, and there is a missing >, hence the syntax error. Then, when foo_negative is instantiated with [T = X], there is another error because X::foo is not a member template.
But why does it think v.foo is a member template? This ambiguity is precisely what the template keyword is for: if I wrote v.template foo, then I would be explicitly telling C++ to expect a member template, but I didn’t use the template keyword! I didn’t refer to a member template, so it should assume that it’s a regular member. The fact that there’s a function of the same name as the member shouldn’t have any effect. Why does it? It can’t be a bug in the compiler because GCC and clang are consistent.
In Clang, this was PR11856, which was fixed ~2.5 months ago. Clang trunk and Clang 3.1 do not report any errors with this code. The Clang bug includes an explanation of why this code was being rejected, and why the code is correct, reproduced here (slightly tweaked to address your case):