对 C++ 嵌套依赖类型名称感到困惑
Confused about C++ nested dependent type name
Effective C++告诉我遇到嵌套的依赖类型名时最好使用typename
。
下面的示例代码很容易理解:
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;
...
}
然而,在模板 class BST 中添加使用别名后,关键字 typename
似乎不再是必需的了。
在这里你可以看到:
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;
...
}
有谁能弄明白吗?
该效果不直接通过 using
与类型别名相关联,它是当前实例化成员的名称查找的结果。
在 BST
中,BST
和 BST<ElementType>
表达式都引用当前实例化,并且可以在不需要前缀 typename
的情况下找到它的成员,你可以做:
template <typename ElementType>
void BST<ElementType>::some_func() {
BST::NodePtr ptr; // or
BST<ElementType>::LinkNode * ptr2;
}
结果是一样的。但现在假设 some_func
也是一个模板成员函数,定义为:
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)
}
现在 (1) 和 (2) 都不会编译,因为 B<T>
不再是当前实例,因此在这些情况下你需要 typename
.
标准的相关部分[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. [...]
Effective C++告诉我遇到嵌套的依赖类型名时最好使用typename
。
下面的示例代码很容易理解:
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;
...
}
然而,在模板 class BST 中添加使用别名后,关键字 typename
似乎不再是必需的了。
在这里你可以看到:
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;
...
}
有谁能弄明白吗?
该效果不直接通过 using
与类型别名相关联,它是当前实例化成员的名称查找的结果。
在 BST
中,BST
和 BST<ElementType>
表达式都引用当前实例化,并且可以在不需要前缀 typename
的情况下找到它的成员,你可以做:
template <typename ElementType>
void BST<ElementType>::some_func() {
BST::NodePtr ptr; // or
BST<ElementType>::LinkNode * ptr2;
}
结果是一样的。但现在假设 some_func
也是一个模板成员函数,定义为:
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)
}
现在 (1) 和 (2) 都不会编译,因为 B<T>
不再是当前实例,因此在这些情况下你需要 typename
.
标准的相关部分[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. [...]