C++ typename 的双重含义

1.模板类型参数申明

使用模板时,在申明模板类型参数时,我们经常有如下两种申明方式:

// 方式一
template <class T> CTest;

// 方式二
template <typename T> CTest;

这两种写法并没有任何区别,都表示 T 是模板类型参数,可以是任何类型,包括用户自定义类型或是语言的基本类型。虽然用于模板类型参数申明时作用完全相同,但是仍建议使用 typename,因为 typename 的字面意义即表示类型名称,更加符合其语义。而 class 则多用于类的申明,而非模板类型参数。当然,如果原有项目中均使用 class,那么请与原有项目风格保持一致。

2.嵌套从属类型名称(nested dependent type name)须使用typename

在 template 声明式中,用于申明模板类型参数时,class 与 typename 作用完全一致。当然,因为前者字符数少,可能会有人倾向于使用 class。但有些时候,typename 却是不可被替换成 class。

假设有个函数模板,接受一个容器 C 为参数,这个容器内部定义了一个类型 a。STL 容器内部会定义 5 种迭代器型别(iterator_category, value_type, difference_type, pointer, reference),即迭代器中定义的类型。这里a可以是其中任何一个,也可是用户自定义类型,但假设不是基本类型。现在看这个函数模板的定义:

template<typename C>			// 建议使用 typename
void func(const C& container)  {
	...
	C::a* x;
	...
}

考虑上面模板定义式中间那行代码,对于开发者而言,可以很明显地推断出代码的含义,x是一个a类型的指针。但是对于编译器而言,在没有明确 C 的定义之前,是无法确定a是一个嵌套于 C 中的类型,其实a可能是 C 内一个静态成员变量,假设x刚好是一个全局变量,那么这行代码也可以由编译器解析为两数相乘。

编译器面对这样的代码如何处置?编译器会这样处理:如果在template中遇到一个嵌套从属类型名称,即依赖于模板类型参数的类型,放在上面例子中对应 C::a,C::a 依赖于模板类型参数 C,它便假设这个名称不是个类型,除非显示告诉编译器。所以缺省情况下嵌套从属类型名称不是类型。如何显示告知呢,可以使用 typename,这是它的第二重意义。在此对之前假设 a 不是基本类型,因为基本类型并不依赖其它类型。

正确的函数模板定义如下:

template<typename C>
void func(const C& container) {
	//...
	typename C::a * x;	//在行首加上typename即可
	//...
}

到这里,想必对 typename 的第二重含义已经基本了解,这也是 typename 与 class 的不同之处,模板中当出现嵌套从属类型名称时须使用 typename 帮助编译器识别。

3.规则之外

模板中当出现嵌套从属类型名称时须使用 typename 帮助编译识别,这一规则也存在例外。typename 不可以出现在 base classes list(所继承的基类成员列表)内的嵌套从属类型名称之前,也不可以在 member initialization list(成员初始化列表)中作为 base class 修饰符。例如:

template<typename T>
class Derived: public Base<T>::Nested { 			//基类成员列表中不允许使用 typename
public:
    explicit Drived(int x) : Base<T>::Nexted(x)  { 	//成员初始化列表中不允许使用 typename
        typename Base<T>:: Nexted temp;	//这里可以
    }
};

4.小结

(1)申明模板参数时,class 和 typename 可以互换,建议使用 typename,因为从字面更加符合语义;
(2)嵌套从属类型名称(nested dependent type name)须使用 typename 来标识,但不能在所继承的基类成员列表和成员初始化列表中使用。


参考文献

[1] Effective C++:改善程序与设计的55个具体做法(第3版 中文版)[M].条款四十二:了解typename的双重意义
[2] 陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008.C6.9 typename的用法
[3] 《STL源码剖析》笔记:迭代器

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值