C++ confusing attribute name for member template

c++, templates

Solution

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):

The paragraph that matters here is [basic.lookup.classref]p1:

"In a class member access expression (5.2.5), if the `.` or `->` token is immediately followed by an identifier followed by a `<`, the identifier must be looked up to determine whether the `<` is the beginning of a template argument list (14.2) or a less-than operator. The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template."

Since `v` is dependent, presumably the identifier is not found so we consider what happens if we look in the context of the entire postfix-expression. Since we find a function template, we should not conclude that we have the start of a template-id.

Problem

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.

Original source

Related problems