Invalid dependent template template template output - thinks I'm trying to use std :: set

I have a class template that inherits from a base class template.

The base class template has a data member with a member function template that I want to call from my superclass.

I know that in order to eliminate the member function template call, I must use the template keyword, and I must explicitly reference this in the superclass.

this->base_member_obj.template member_function<int>();

All this is good and good, except that the code base used made a rather unsuccessful error when importing the entire namespace std , and the template member function that I am trying to call is called set . Somewhere within the scope of std::set included, and this makes GCC think I'm trying to declare std::set instead of calling the set member function.

GCC 4.7 gives error message invalid use of 'class std :: set'

The following is an example error . If you comment out using namespace std , the code compiles.

Unfortunately, it is impossible for me to execute the entire codebase, delete every call using namespace std and the prefix of every call to something inside the std namespace using std::

Is there another way?

 #include <set> using namespace std; // comment this out to compile fine struct blah { template<typename T> void set() { } }; template<typename T> struct base { blah b; }; template<typename T> struct super : base<super<T>> { void fun() { this->b.template set<int>(); // this line breaks } }; int main() { super<int> s; s.fun(); return 0; } 
+6
c ++ stl templates
source share
3 answers

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.

+3
source share

Try the following:

 this->b.blah::template set<int>(); // this line breaks 
+5
source share

You have two options:

  this->b.blah::template set<int>(); // ^^^^^^ Be very explicit what set you want 

As an alternative, do not use using namespace (best option).

+3
source share

All Articles