Effective C++ 条款42:了解 typename 的双重意义
文章目录
- 条款42:了解 `typename` 的双重意义
- 示例 1:指涉嵌套从属类型
- 示例 2:`typename` 与 `class` 互换
- 示例 3:在基类列表和成员初始化列表中使用
- 使用规则
条款42:了解 typename
的双重意义
关键字 typename
在 C++ 中有两种主要用途:
-
标识嵌套从属类型名称
当指涉模板中的嵌套从属类型名称时,必须使用关键字typename
来明确表示该名称是类型,而不是变量或其他实体。 -
声明模板参数
在声明模板参数时,typename
和class
关键字可以互换使用。
示例 1:指涉嵌套从属类型
在模板中,当使用嵌套从属类型名称(即依赖于模板参数的类型名称)时,需要在名称前添加 typename
:
template <typename C> void print2nd(const C& container) { if (container.size() >= 2) { typename C::const_iterator iter(container.begin()); std::cout << *iter << std::endl; } }
分析:
C::const_iterator
是C
的嵌套类型。- 编译器需要通过
typename
明确告知,C::const_iterator
是类型,而不是静态成员或其他实体。
示例 2:typename
与 class
互换
在声明模板参数时,可以使用 typename
或 class
,两者等效:
template <class T> class MyClass { // 使用 class 声明模板参数 }; template <typename T> class AnotherClass { // 使用 typename 声明模板参数 };
示例 3:在基类列表和成员初始化列表中使用
在基类列表和成员初始化列表中,不允许将 typename
用作基类修饰符:
template <typename T> class Derived : public Base<T>::Nested { // 错误:不允许 "typename" public: explicit Derived(int x) : Base<T>::Nested(x) // 错误:不允许 "typename" { typename Base<T>::Nested temp; // 正确:在函数体内需要 "typename" } };
总结:
- 在基类列表和成员初始化列表中,嵌套从属类型会被默认为类型。
- 在函数体内,需要明确使用
typename
标识嵌套从属类型名称。
使用规则
-
必须使用
typename
的场合:- 指涉模板中的嵌套从属类型名称。
-
不得使用
typename
的场合:- 在基类列表中。
- 在成员初始化列表中。
-
typename
与class
的选择:- 二者在模板参数声明时可以互换,选择哪一个是风格问题。
- 对于代码一致性,推荐统一使用一种风格,例如偏好
typename
。
通过正确理解和使用 typename
,可以有效避免编译错误,确保代码的清晰和可维护性。