Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template dependent base member is not resolved properly

This question is a follow up of Moving a member function from base class to derived class breaks the program for no obvious reason (this is a prime example of why one shouldn't use using namespace std;)

where the answers suggested qualifying by this-> a dependent template name (which indeed is the way to go when referring to such dependent members). However, there seems to be an issue, so I'll list 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

The perplexing thing is that even though this->bitset should refer to the member B<T>::bitset, the compiler is still confused and believes that we try to refer to std::bitset<std::size_t>. The error appears on both gcc6 and clang3.7. Any ideas why this happens? 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

This looks to me like a parsing/name lookup bug. If we replace < by any other comparison operator (thanks @Leon for the remark), e.g.

return this->bitset == 32; 

the program compiles. So I guess in this->bitset < 32 the parser believes that we are trying to instantiate a template (the < sign), and we forgot to close the >. But again have no idea if this is indeed a bug or that's how the language is suppose to work.

like image 240
vsoftco Avatar asked Nov 07 '16 17:11

vsoftco


People also ask

What does template typename t mean?

template <typename T> ... This means exactly the same thing as the previous instance. The typename and class keywords can be used interchangeably to state that a template parameter is a type variable (as opposed to a non-type template parameter).

How to define template class in cpp?

Templates in C++ is an interesting feature that is used for generic programming and templates in c++ is defined as a blueprint or formula for creating a generic class or a function. Simply put, you can create a single function or single class to work with different data types using templates.

How template works in c++?

While using a template in C++, you pass a data type as a parameter. Thus, instead of maintaining multiple codes, you have to write one code and give the data type you want to use. C++ templates use two primary keywords, 'template' and 'typename,' where the 'typename' can be replaced with the 'class' keyword.

What does template class mean?

Definition. As per the standard definition, a template class in C++ is a class that allows the programmer to operate with generic data types. This allows the class to be used on many different data types as per the requirements without the need of being re-written for each type.


1 Answers

tl;dr it looks like this is a deliberate decision, specifically to support the alternate syntax you already used.

An approximate walkthrough of the standardese below:

this-> B <
         ^
  • this could be either the start of a template id or a less-than, so let's check both!
    1. this->B does name something, but it's a template B<T>, so keep going
    2. B on it's own also names something, a class template B<T>
    3. wait, they're the same thing! That means we're using this->B<T> as a qualifier, and it isn't a less-than after all

In the other case,

this->bitset

proceeds identically until the third step, when it realises there are two different things called bitset (a template class member and a class template), and just gives up.


This is from a working draft I have lying around, so not necessarily the most recent, but:

3.4.5 Class member access [basic.lookup.classref ]

1 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. If the lookup in the class of the object expression finds a template, 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 class of the object expression is used, otherwise
  • if the name is found in the context of the entire postfix-expression and does not name a class template, the name found in the class of the object expression is used, otherwise
  • if the name found is a class template, it shall refer to the same entity as the one found in the class of the object expression, otherwise the program is ill-formed.

So, in any expression like this->id < ..., it has to handle cases where id<... is the start of a template identifier (like this->B<T>::bitset).

It still checks the object first, but if this->id finds a template, further steps apply. And in your case, this->bitset is presumably considered a template as it still depends on T, so it finds the conflicting std::bitset and fails at the third bullet above.

like image 72
Useless Avatar answered Oct 16 '22 06:10

Useless