《Effective C++》学习笔记——条款42
2016-03-17 23:30
525 查看
七、模板与泛型编程
条款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++ primer 第五版 笔记前言
- 那些年,我还在学习C# 学习笔记续
- Ruby 魔法 学习笔记之一
- sqlserver 数据库学习笔记
- CSS学习笔记Padding 属性中参数的定义与使用
- prototype 1.5 & scriptaculous 1.6.1 学习笔记
- prototype 学习笔记整理
- Oracle学习笔记(六)
- 关于SQLServer2005的学习笔记 XML的处理
- Jquery 基础学习笔记
- ExtJs 学习笔记基础篇 Ext组件的使用第1/2页
- linux Shell学习笔记第五天
- Jquery 学习笔记(二)
- PHP入门学习笔记之一
- 那些年,我还在学习C# 学习笔记
- Ruffy javascript 学习笔记
- JavaScript 学习笔记(十六) js事件
- JavaScript 学习笔记(十二) dom
- JavaScript 学习笔记(十一)
- JavaScript 学习笔记 Black.Caffeine 09.11.28