七、模板与泛型编程
条款42、了解 typename 的双重定义
当我们声明template类型参数,class 和 typename 的意义完全相同,比如:
template<class T> class Widget;
template<typename T> class Widget;
但是,C++并不总是把他俩看做等价的。
例1
假设,我们有个 template function,接受一个STL兼容容器为参数,容器内持有的对象可被赋值为int。
template<typename C>
void print2nd(const C& container)
{
if(container.size() >= 2) {
C::const_iterator iter(container.begin());
++iter;
int value = *iter;
std::cout<<value;
}
}
iter的类型是 C::const_iterator,实际的类型取决于参数C。
template内出现的名称如果相依于某个template参数,称之为 dependent name(从属名称),如果从属名称在 class 内呈嵌套状,我们称它为嵌套从属名称,就像 iter一样。
而另一个local变量 value,是int类型,并不依赖任何template参数,这叫 non-dependent name(非从属名称)。
嵌套从属名称 可能会导致 解析困难。
template<typename C>
void print2nd(const C& container)
{
C::const_iterator* x;
...
}
乍一看,变量x,是我们声明的一个指向 C::const_iterator的指针变量。
因为,我们已经知道了 C::const_iterator是一个类型,但是,如果它不是一个类型呢?如果 C有个static成员变量而碰巧被命名为 const_iterator,或如果 x 碰巧是一个global变量名称,那么里面的 * 可能就不是指针相关,而是 乘号。
虽然,听起来荒谬,但实际上是有可能的。
当然,C++有规则可以解析这个歧义状态:如果解析器在template中遭遇一个嵌套从属名称,它便假设这名称不是个类型,除非你告诉它是。所以,缺省情况下嵌套从属名称不是类型。
就是在 你想在template中指涉一个嵌套从属类型名称,就必须在紧邻它的前一个位置加上关键字 typename。
typename 只被用来验明嵌套从属类型名称,其他名称不该有它存在。
例2
typename 必须作为嵌套从属类型名称的前缀词
这一规则 有一个例外:
typename 不可以出现在 base_class list 内的嵌套从属名称类型名称之前,也不可以 member initialization list(成员初值列)中作为base class修饰符。
template<typename T>
class Derived: public Base<T>::Neted { // base class list中 不允许 typename
public:
explicit Derived(int x): Base<T>::Nested(x) // mem.init.list 中 不允许 typename
{
typename Base<T>::Nested temp; // 嵌套从属名称既不在 base class list,也不在 mem.init.list中
...
}
...
};
例3
写一个 function template,让它接受一个迭代器,我们将为这个迭代器所指涉的对象做一份 local副本 temp。
template<typename IterT>
void workWithIterator(IterT iter)
{
typename std::iterator_trains<IterT>::value_type temp(*iter);
...
}
这里,因为 std::iterator_trains::value_type 是嵌套从属名称,所以前面加了关键字 typename。
这个东西 —— std::iterator_trains::value_type,有些长,在实际编程中,可能很多人必须换打这么长的东西,所以用到了 typedef:
template<typename IterT>
void workWithIterator<IterT iter)
{
typedef typename std::iterator_trains<IterT>::value_type value_type;
value_type temp(*iter);
...
}
typename相关规则在不同编译器上有不同的实践,所以在移植上可能会有些许微妙的问题存在。
请记住
- 声明template参数时,前缀关键字 class 和 typename 可互换
- 请使用关键字 typename 标识嵌套从属类型名称;但不得在 base class list 或 member initialization list 内以它作为base class 修饰符
本文探讨了C++中typename关键字的双重定义及其在模板编程中的应用,尤其是在处理嵌套从属名称时的重要性。
796

被折叠的 条评论
为什么被折叠?



