[Effective C++]条款42 typename

[复制链接]
发表于 2025-11-13 22:10:45 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本文初发于 “天目中云的小站”,同步转载于此。
  条款42 : 相识typename的双重意义

   本条款中我们将相识typename的两种利用场景, 对typename的内涵及利用加深认知.
  template声明式

在template的声明中, template<class T>和template<typename T>都是被允许的, 这两种写法并没有任何差异, C++对这两种写法等量齐观, 但是在真正利用中, 作者还是发起在传入自界说类时用class, 在传入恣意范例(包罗int等)时用typename, 如许会增长代码的可读性.

针对嵌套附属范例名称的应用

先让我们认识嵌套附属范例名称的界说 :


  • 附属 : 依靠于某个template参数.
  • 嵌套 : 在class内呈嵌套状.
  • 附属嵌套范例名称 : 在class内呈嵌套状且依靠于某个template参数的范例名称.
我们通过下面的代码来明确 :
  1. template<typename C>                           
  2. void print2nd(const C& container)              
  3. {                                               
  4.   if (container.size() >= 2) {
  5.      C::const_iterator iter(container.begin());  // 这里的C::const_iterator便是从属嵌套类型名称
  6.      ++iter;                                    
  7.      int value = *iter;                        
  8.      std::cout << value;                        
  9.   }
  10. }
复制代码
这段代码是无法通过编译的, 我们只有在前头加上typename才可以通过编译, 这是由于编译器早先并不确定C::const_iterator是一个范例名称, 以是当你明确指明其是一个范例名称之后, 编译器就可以正常运作了.
  1. typename C::const_iterator iter(container.begin()); // 这样就可以了
复制代码


  • 以是为什么编译器无法确定这是一个范例名称呢?
    实在是为了代码的严谨性, 我们举一个非常一点的例子 :
    1. C::const_iterator* x;
    复制代码
    当我们写下如许的代码时, 编译器并不知道const_iterator是C中的范例还是成员变量, 如果它是成员变量的话, 那么这实在是一个乘法运算式, *是乘号; 如果他是范例, 那么这实在就是一个界说式, *代表着指针. 这两种情况都完全合法, 因此必要步调员明确指出其毕竟是什么才行.

两个例外

在一样平常情况下, typename必须作为嵌套附属范例名称的前缀词, 这一规则的例外是, typename不可出如今继承语句和初始值列表中, 这是C++中定死的, 没有须要去相识为什么, 记取就行.
  1. template<typename T>
  2. class Derived: public Base<T>::Nested { // 继承语句不可加typename
  3. public:                                 
  4.   explicit Derived(int x)
  5.   : Base<T>::Nested(x)                  // 初始值列表不可加typename
  6.   {                                    
  7.     typename Base<T>::Nested temp;      // 这里可以加
  8.     ...                              
  9.   }                                    
  10. };
复制代码

typename和typedef的组合利用

我们知道了typename会与嵌套附属范例名称绑定, 而且其着实一些情况下嵌套附属范例名称是很长的, 我们会风俗把typedef与typename组合, 将一个范例的誊写长度紧缩, 我们通过下面的例子相识 :
  1. template<typename IterT>
  2. void workWithIterator(IterT iter)
  3. {
  4.   typedef typename std::iterator_traits<IterT>::value_type value_type;
  5.   value_type temp(*iter);
  6.   ...
  7. }
复制代码
这是这个组合的经典用法, 在STL标准库中就有大量的利用.
这里通过typedef将typename std::iterator_traits<IterT>::value_type这个云云长的范例紧缩到value_type, 不消想也肯定会镌汰大量的代码量. 至于为什么会有这么长的范例, 这与iterator_traits的萃取功能有关, 简朴来说就是IterT是一个迭代器范例,而iterator_traits可以根据iterT通过value_type萃取出迭代器所指向资源的真实范例T. 我们将在条款47中再作讨论这部门内容, 如果想深入学习的话也可以去STL源码分析中研读.

请记取 :



  • typename作为template参数时, 和class意义完全类似.
  • typename必须作为嵌套附属范例名称的前缀词, 除非在继承语句和初始值列表中.
  • 将typedef和typename组合可以减小代码复杂度.
by 天目中云
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表