现在的位置: 首页 > 综合 > 正文

嵌套依赖类型名

2014年02月13日 ⁄ 综合 ⁄ 共 1338字 ⁄ 字号 评论关闭

原文:点击打开链接

关于C++中模版常用的的typename和class,先写结论吧:

  • 在声明模版参数时,class和typename关键是等价的,可以相互替换。
  • 在涉及“嵌套依赖类型名”(nested dependent type name)的时候,必须用typename关键字去标识。
  • 规则2有个例外,就是在继承列表或者成员初始化列表中的基类初始化时,可以不用typename去标识“嵌套依赖类型”。
在早期的C++标准中,模版参数的关键字是通过class来标识的,后来引入了typename关键字。typename关键字本质上是标识一个类型,所以在模版参数定义时可以代替class。然而typename关键字有更重要的作用,即用来标识“嵌套依赖类型”,那么什么是“嵌套依赖类型”,可以看下面一个例子:
1
2
3
4
5
6
template<typename
T>
void
print2nd(
const
T& container)
{
    T::const_iterator * x;
    ...
}
在print2nd这样一个模版函数中,变量x的类型依赖于模版参数T,因此它的具体类型只有在编译时的模版推导过程(template deduction)中才能够被确定。这样的类型称之为“嵌套依赖类型”(nested dependent type name),但是很遗憾,编译器并不知道const_iterator是一个类型还是一个静态变量。在默认情况下,C++标准会让编译器会把const_iterator做为一个静态变量处理(你没看错,编译器很多时候比我们想象的愚蠢),所以你会得到如下的编译错误:
1
2
3
leoxiang@debian:~$ g++ -std=c++0x
test.cpp
test.cpp: In
function ‘void print2nd(const T&)’:
test.cpp:16: error: ‘x’ was not declared
in this scope
这时候,就需要typename关键字出场了,它显式的告诉编译器T::const_iterator是一个类型,因此这一行的语义就是声明一个嵌套依赖类型的局部变量,而不是一个静态变量乘以x。
1
2
3
4
5
6
template<typename
T>
void
print2nd(
const
T& container)
{
    typename
T::const_iterator * x;
    ...
}
好了,最后说一个不需要使用typename的例外:就是在继承列表或者成员初始化列表中的基类初始化时,可以不用typename去标识“嵌套依赖类型”。说起来比较绕,看例子就明白了:
1
2
3
4
5
6
7
8
9
10
template<typename
T>
class
Derived: public
Base<T>::Nested //in base class list, no typename
{
 public:
  explicit
Derived(int
x)
  : Base<T>::Nested(x)
//in member init list, no typename
  {
   typename
Base<T>::Nested temp; //nested dependent type, need typename
  }
};

抱歉!评论已关闭.