Well, this is quite confusing for us C ++ pushers.
This is a bug in g ++ that also appears in Comeau Test Drive. This is not a flaw in the language itself. The problem is related to the left-sided nature of the parsing and the way the two-dimensional ambiguity of the C ++ language.
The right to use the non-member, non-base class template in the nested name specifier for typedef for the base class template. In this context, after -> :
a class template may appear without special regard to the available class
#include <tuple> template< typename t > struct get_holder { typedef std::tuple< t > type; }; template< typename ... ts > struct inherits : get_holder< ts >::type ... { inherits( ts ... v ) : get_holder< ts >::type( v ) ... {} template< typename tn > void assign_one( inherits &o ) { this->get_holder< tn >::type::operator= ( o ); } // <- here! }; int main() { inherits< int, char, long > icl( 3, 'q', 2e8 ); icl.assign_one< char >( icl ); }
Since C ++ is parsed from left to right, when the parser gets into -> , it must solve get_holder before continuing. For this, the standard has a special sentence Β§3.4.5 / 1 [basic.lookup.classref]:
In an expression for accessing a class member (5.2.5) , if. or β the token followed by the identifier, and then the identifier <, should be checked to determine if the argument list of the template (14.2) is the beginning or less than the operator. The identifier is first looked up in the object expression class. If the identifier is not found, then it is looked in the context of the whole postfix expression and we will call the class template. If a search in the object's expression class finds a pattern, the name is also looked up in the context of the entire postfix expression and
- if the name is not found, the name found in the object class uses an expression, otherwise
- if the name is found in the context of the entire postfix expression and does not name the class template, the name found in the class is the expression of the object, otherwise
- if the found name is a class template, it must refer to the same object as the one found in the object expression class, otherwise the program will be poorly formed.
Emphasize mine - it looks like g ++ is following this logic, even though the template keyword is displayed between . and identifier set . In addition, assuming that he was following this route, he should mark the ambiguity as an error, and not try to choose a non-term.
There seems to be a mistake in the standard wording on how to act when the template keyword appears, but this should not cause the chaos that you see. Β§14.2 [temp.names]:
When then the member template specification appears. or β in a postfix expression or after a sub-name specifier in an identifier with qualification, and the postfix-expression or qualified-box explicitly depends on the template parameter (14.6.2), but does not apply to the member of the current instance (14.6.2.1), the name of the member template must have a keyword template prefix. Otherwise, it is assumed that the name is called a non-pattern.
Emphasize that this text is in error and should read "the name is not considered the name of the participant template," because, as shown in my illustration above, it can be part of the nested name specifier. If the text is taken literally as it is, then it can be interpreted as meaning that the template keyword is required in my illustration, therefore, it can point to the next template that is not a member (provided that the language supports such a construction in general), and then your program may be misinterpreted, as can be seen from g ++.
But the intention of the design is clear, and you do not need to add an artificial nested name specifier blah:: , although this is a legitimate solution.