条款42、typename的双重意义
来源:互联网 发布:java io深入 编辑:程序博客网 时间:2024/06/08 11:52
如下:template<classT>class Widget; //使用”class”template<typenameT>class Widget; //使用”typename”
虽然使用了不同的关键字,但从C+的角度来说,声明模板参数时,关键字class 和typename意义完全相同。
然而C+并不把class和typename视为等价。有时你一定得使用typename.
考虑下面一个函数模版,接受一个STL兼容容器为参数,容器内持有对象可赋值为ints。假设这个函数仅仅是打印其第二元素值.(这个函数无意义,只是为了论述)template<typename C>void print2(const C& container) //打印容器第二元素{ if(container.size()>2) { C::const_iterator it(container.begin()); //第一个元素迭代器 ++it; int val=*it; std::cout<<val; }}
上述代码强调两个局部变量,val 和it 。it类型为c::const_itertor,实际类型取决于模版参数C。模版内出现的名称如果相依于某个模版参数,称之为从属名(depedent names)。如果该名称在class内嵌套,则称嵌套从属名称(nestde dependent name),如C::const_iterator(嵌套从属类型).
另一个local变量是val,为int类型。不依赖于任何模版参数名。称之为非从属类型(non-dependent names).
但嵌套从属名称可能会导致解析困难,如下:template<typename C>void print2(const C& container) //打印容器第二元素{ C::const_iterator * x;…}
似乎是声明一个指针x,其类型为C::const_itertor(这是在我们已经知道它是个类型的情况下)。
但如果C::const_itertor不是个类型呢?如C刚好有个static成员变量而刚好命名为const_iterator,或x碰巧是个全局变量名?在这种情况下上面情况也许就不是声明一个局部变量,而是一个相乘的动作。
很明显,在知道C之前,无从知道C::const_iterator是否为类型。C+规则:如果解析在模版中遇到一个嵌套从属名称,它便假设这个名称不是类型。所以在缺省情况下,在缺省情况下嵌套从属名不是类型。再看:template<typename C>void print2(const C& container) //打印容器第二元素{ if(container.size()>2) { C::const_iterator it(container.begin()); //该名被假设为非类型….}
很显然上述代码不合法,it只有在C::const_iterator声明为类型时才合理,正确的做法是:template<typename C>void print2(const C& container) //打印容器第二元素{ if(container.size()>2) { typename C::const_iterator it(container.begin()); //该名被假设为非类型….}
一般规则为:想在模版中涉及一个嵌套从属类型名,就必须在其前面加个类型关键字typename
例外情况:typename只用来验明嵌套从属类型名称,其他名不该有它存在。如下此函数模版接受一个容器和一个“指向该容器”的迭代器template<typename C> //可使用class或typenamevoid f(const C& container //不能使用typename typename C::iteratorit); //一定使用typename
上述C并不是嵌套从属类型名,(它并不嵌套于任何“取决于template参数”的东西内),所以声明container并不需要以typename为前导,而C::iterator必须以typename为前导。
“typename必须做为嵌套从属类型前缀”这一规则的例外是:typename不可以出现在基类列表内的嵌套从属类型前,也不可在成员初始列中作为基类修饰符。如:template<typename T>class Derived: public Base<T>::Nested //基类列表中不允许typename{ public: explicitDerived(int x) :Base<T>::Nested(x) //成员初始值列,不允许typename{ typenameBase<T>::Nested tmp; //嵌套从属类型名称 //不在基类列表也不在成员初始值列中,作为基类修饰符必须加上typename …} };
再看一个例子:template<typename IterT>void workWithIterator(IterT iter){ typenamestd::iterator_traits<IterT>::value_type tmp(*iter);…..}
typenamestd::iterator_traits<IterT>::value_type,相当于说“类型为IterT的对象所指之物的类型”。这个语句声明一个局部变量,使用IterT的对象所指的类型,将tmp初始化为iter所指物。比如IterT类型是vector<int>::itertor,则tmp类型就是int.是vector<string>::iterator,tmp类型就为string。由于std::iterator_traits<IterT>::value_type是个嵌套从属类型,故在其之前放置typename。
当然,这个定义太长,我们可以使用typedef,如下:template<typename IterT>void workWithIterator(IterT iter){ typedef typenamestd::iterator_traits<IterT>::value_type value_type;value_type tmp(*iter);…..}
由于typename的相关规则在不同编译器上有不同实现,故在移植性方面也会有小问题。
需要记住的:1、声明模版参数时,关键字class和typename可互换2、使用typename标志嵌套从属类型名。但不得在基类列表和成员初始值列内以它做为基类的修饰符。
0 0
- 条款42:了解typename的双重意义
- 条款42:了解typename的双重意义
- 条款42:了解typename的双重意义
- 条款42:了解typename的双重意义。
- 条款42:了解typename的双重意义
- 条款42、typename的双重意义
- 条款42:了解typename的双重意义
- 条款42:了解typename的双重意义
- Effective C++:条款42:了解typename的双重意义
- 读书笔记《Effective C++》条款42:了解typename的双重意义
- Effective C++ — 条款42:了解typename的双重意义
- Effective C++学习笔记_条款42:了解typename的双重意义
- 了解typename的双重意义
- 了解typename的双重意义
- 了解typename的双重意义
- Effective C++ Item 42 了解 typename 的双重意义
- 《Effective C++》42: 了解 typename 的双重意义
- C++模版typename的双重意义
- 为什么基类的析构函数是虚函数?
- java Native Method
- linux 忘记了root的密码
- hdu1392标准求凸包模板
- UITextField的一些属性
- 条款42、typename的双重意义
- NUMA架构的CPU -- 你真的用好了么?
- iOS中ARC内部原理
- LRU算法
- UIImage的一些属性
- 三出口函数:解决计算几何中的精度问题
- Android多线程的简单使用
- 黑马程序员-流程控制
- android动态布局