Template-specific base element not properly resolved

This question is a continuation. Moving a member function from a base class to a derived class breaks the program for no apparent reason (this is a prime example of why you cannot use using namespace std; )

where the answers suggested qualifying this-> dependent template name (which really is a way to go when accessing such dependent members). However, it seems to be a problem, so I have listed a minimal example that reproduces the problem.

Consider the code:

 #include <iostream> #include <bitset> using namespace std; template<class T> struct B { T bitset{}; }; template<class T> struct D : B<T> { bool foo() { return this->bitset < 32; } }; int main(){} 

Live on coliru

Surprisingly, even if this->bitset should refer to the B<T>::bitset element, the compiler is still confused and believes that we are trying to access std::bitset<std::size_t> . The error appears on both gcc6 and clang3.7. Any ideas why this is happening? Qualifying it with B<T>::bitset works though.

Error (verbatim):

In member function 'bool D<T>::foo(T, std::__cxx11::string)': cpp/scratch/minimal.cpp:24:22: error: invalid use of 'class std::bitset<1ul>'

EDIT

It looks like a parsing / name lookup error. If we replace < with any other comparison operator (thanks @Leon for the remark), for example

 return this->bitset == 32; 

the program is compiled. Therefore, I believe that in this->bitset < 32 analyzer believes that we are trying to create a template ( < sign), and we forgot to close > . But again, I can’t imagine if this is really a mistake or that the language should work.

+7
c ++ c ++ 11 templates
Nov 07 '16 at 17:06
source share
1 answer

tl; dr looks like this is a deliberate solution, specifically to support the alternative syntax that you have already used.

An approximate walkthrough of the standard below:

 this-> B < ^ 
  • it can be either the beginning of the template identifier or less, so let it check both!
    • this->B does something, but it is a template B<T> , so keep moving
    • B on it also has names, a class template B<T>
    • Wait, they are the same! This means that we use this->B<T> as a qualifier, and this is no less than after

Otherwise

 this->bitset 

It proceeds identically until the third step, when it implements two things: bitset (a member of the template class and the class template) and simply returns.




This is from a working draft that I was lying on, so not necessarily the very latest, but:

3.4.5 Access to the class member [basic.lookup.classref]

1 In an access expression to a member of a class (5.2.5), if. or β†’ immediately followed by an identifier, followed by an identifier, the identifier must be looked up to determine whether this is the beginning of the template argument list (14.2) or the less operator. The identifier first looked up in the object expression class. If the identifier is not found, it is then looked in the context of the entire postfix-expression and should name the class template. If a search in the object's expression class finds a pattern , the name also looked in the context of the entire postfix expression and

  • If the name is not found, the name found in the object expression class is used, 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 of the expression of the object, otherwise
  • If the name found is a class template, it must refer to the same object as the one found in the class expression of the object, otherwise the program is poorly formed.

So, in any expression like this->id < ... , it should handle cases where id<... is the beginning of the template identifier (for example, this->B<T>::bitset ).

It still checks the object first, but if this->id finds the pattern, the next steps apply. And in your case, this->bitset seems to be considered a pattern, since it still depends on T , so it detects a conflicting std::bitset and fails in the third mark above.

+7
Nov 07 '16 at 18:18
source share



All Articles