一、typename和class在声明类模板参数或者函数模版参数时,代表的意义是相同的。通常情况下,如果模版的参数要求是class类型(用户自定义类型-user defined type)使用class声明模版参数;如果模版参数可以是任意类型使用typename声明模版参数。
例如:声明一个实现任意类型的两对象相加的函数模版
template<typename T1, typename T2, typename T3>
const T1& add(const T1& a, const T2& b)
{
return a+b;
}
::add()函数在使用过程中的模版参数类型可以是任意类型,但是如果模版参数类型是class类型,那么该class必须支持operator+操作符。
例如:声明一个使用迭代器遍历容器的函数模版
template<class CT>
void travel(const CT& conT)
{
typename CT::const_iterator beginIter = conT.begin();
typename CT::const_iterator endIter = conT.end;
for(;beginIter!=endIter;++beginIter)
{
std::cout<<*beginIter;
}
}
travel()在使用过程中模版参数类型必须是class类型而且支持const_iterator才可以。
二、typename其他用法
在模版中有种情况必须使用typename
拥有嵌套依赖名时:
像travel里面的beginIter、endIter这样的变量依赖了CT容器的迭代器的类型(C++中迭代器也是一个模版),而且C++模版中像CT::const_iterator并不视为一种类型而是static对象。要想把CT::const_iterator当作一个类型使用,必须使用typename前缀修饰。
嵌套依赖名省略typename的情况:
a、基类列表
b、成员列表初始化
例:
template<typename T>
class Derived: public Base<T>::UserDefinedType { // 模版实例Base<T>依赖模版参数类型T,Base<T>::UserDefinedType应该使用typename修饰,
// 但是因为它在基类列表中所以省略typename
public:
explicit Derived(int x)
: Base<T>::UserDefinedType(x) // 程序列表初始化处省略typename修饰
{
typename Base<T>::UserDefinedType temp; // typename修饰UserDefinedType是一个class类型
}
};