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.
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).
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.
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.
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.
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->B
does name something, but it's a template B<T>
, so keep goingB
on it's own also names something, a class template B<T>
this->B<T>
as a qualifier, and it isn't a less-than after allIn 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With