Reputation: 511
Effective C++ told me that I'd better use typename
when encountered nested dependent type name.
The following example code is easy to understand:
template <typename ElementType>
class BST {
private:
class LinkNode {
public:
ElementType data;
LinkNode *left, *right;
explicit LinkNode() {}
};
public:
void some_func();
}
template <typename ElementType>
void BST<ElementType>::some_func() {
// or `using NodePtr = typename BST<ElementType>::LinkNode *;`
typedef typename BST<ElementType>::LinkNode * NodePtr;
...
}
However, after I added using aliases in the template class BST, it seemed that keyword typename
is not neccessary anymore.
Here you can see:
template <typename ElementType>
class BST {
private:
class LinkNode {
public:
ElementType data;
LinkNode *left, *right;
explicit LinkNode() {}
};
using NodePtr = LinkNode *; // the only difference between these two code blocks
public:
void some_func();
}
template <typename ElementType>
void BST<ElementType>::some_func() {
// typename is not neccessary here!
BST<ElementType>::NodePtr ptr;
...
}
Does anyone could figure out that?
Upvotes: 4
Views: 379
Reputation: 11250
That effect is not directly tied to type alias through using
, it's a result of name lookup for member of the current instantiation.
Inside BST
both BST
and BST<ElementType>
expression refer to the current instantiation and the members of it can be found without the need of the prefix typename
you could do:
template <typename ElementType>
void BST<ElementType>::some_func() {
BST::NodePtr ptr; // or
BST<ElementType>::LinkNode * ptr2;
}
resulting in the same thing. But now let assume that some_func
is also a template member function defined as:
template <typename ElementType>
struct BST {
class LinkNode { /*...*/ };
using NodePtr = LinkNode *;
template <typename T>
void some_func();
};
template <typename ElementType>
template <typename T>
void BST<ElementType>::some_func() {
BST<T>::NodePtr ptr; // (1)
BST<T>::LinkNode * ptr2 // (2)
}
Now neither (1) nor (2) will compile because B<T>
is no longer the current instantiation, hence in these cases you need typename
.
The relevant part of the standard [temp.res]/7
:
Within the definition of a class template or within the definition of a member of a class template following the declarator-id, the keyword typename is not required when referring to the name of a previously declared member of the class template that declares a type or a class template. [...]
Upvotes: 1