C++ template inheritance issue with base types
I have the following cod开发者_运维百科e and it fails to compile
template < typename T >
class Base
{
public:
typedef T * TPtr;
void func()
{
}
};
template < typename T >
class Derived : public Base< T >
{
public:
using Base< T >::TPtr;
using Base< T >::func;
TPtr ptr;
};
int main( int c, char *v[] )
{
Derived< int > d;
d.func();
}
The compiler issues the following.
t.cpp:16: error: 'TPtr' does not name a type
t.cpp:16: note: (perhaps 'typename Base<T>::TPtr' was intended)
Now I know I could simply do as the compiler is suggesting but I can't understand why the
using Base< T >::TPtr;
doesn't work.
If I comment out the "TPtr ptr
" line then it compiles, proving that the "using Base< T >::func;
" statement works.
Any ideas?
Base< T >::TPtr
is a so-called dependent name so you need to prefix it with typename
to make the declaration work.
Additionally, using
doesn’t work with typename
so you need to use a typedef
instead:
typedef typename Base<T>::TPtr TPtr;
The issue is that the compiler can’t decide – without knowing what T
is! – whether TPtr
in this context names a type or a variable/function. To avoid ambiguities, it always assumes the latter, unless explicitly told otherwise (hence the need for typename
).
This is part of a defect. While C++03 did provide using typename
, it did not provide the necessary rules to say that the name declared by the using declaration is a type-name. It just provided the instrument to say that the name referenced in the using declaration is a type-name. So you can do in fact the following, but with varying success among compilers. Some will make it work, but some won't.
template < typename T >
class Derived : public Base< T >
{
public:
using typename Base< T >::TPtr;
using Base< T >::func;
// up to here it's alright
TPtr ptr;
// but this may only work on some compilers
};
This issue has been fixed for C++0x. For C++03, the way to work around it is to use a typedef
instead.
I can't understand why the:
using Base< T >::TPtr;
doesn't work.
Due to possible template specialization, Base< T >::TPtr
can be anything: a type name, variable name, function, etc.
With the keyword typename
you tell compiler that it can be a type name only.
Here is a decent explanation of what sort of ambiguities it serves to resolve. Scroll down to "The Problem", it covers your case precisely.
When you write TPtr ptr;
it is seen as Base<T>::TPtr
and the compiler will assume that this is a member variable of Base<T>
or a method of Base<T>
(this is what it will do because Base<T>::TPtr
is a 'dependant name' and unfortunately in this case the compiler will assume variable or function instead of type) thus making the declaration invalid.
The keyword typename
allow the compiler to know explicitly that TPtr
names a type.
精彩评论