声明template参数时,前缀关键词class和typename可互换。也就是说以下两个没有区别:

(1)template<class T>class Widget;

(2)template<typename>class Widget。

然而C++并不总是把class和typename视为等价。有时一定得使用typename。

这种时机就是:任何时候当想要在template中指涉一个嵌套从属类型名称,就必须在紧邻它的前一个位置放上关键字typename,只有如下一个例外:不得在base class list(基类列)或member initialization list(成员初值列)内以它作为base class修饰符。其中:template内出现的名称如果相依于某个template参数,称之为从属名称。如果从属名称在class内呈嵌套状,我们称它为嵌套从属名称。C::const_iterator(看下面例子)就是这样的一个名称。实际上它还是个嵌套从属类型名称,也就是个嵌套从属名称并且指涉某类型。看下面例子:

template <typename C>
void print2nd(const C& container)
{
 if(container.size()>=2)
 {
  C::const_iterator iter(container.begin());
  ++iter;
  int value = *iter;
  cout<<value<<endl;
 }
}

嵌套从属名称有可能引起解析困难。如下面的例子(将上面的改一下):

template <typename C>
void print2nd(const C& container)
{
 C::const_iterator* x;
 ...
}

按照正常的理解我们应该是声明了一个x的局部变量,但是前提是我们知道C::const_iterator是个类型,但是万一不是呢,比如C是个类并且它有一个const_iterator的静态成员变量呢而且x又是一个全局变量,那么上面的就是一个相乘的动作,即C::const_iterator乘以x。引起歧义。

在我们知道C是什么之前,没有任何办法可以知道C::const_iterator是否是一个类型。而当编译器开始解析template print2nd时,尚未知C是什么东西。C++有个规则可以解析此一歧义状态:如果解析器在template中遭遇一个嵌套从属名称,它便假设这名称不是一个类型,除非你告诉它是。所以缺省情况下嵌套从属名称不是类型。此规则有个例外,稍后会谈到。我们告诉它是只需在C::const_iterator前加上关键字typename即可。

注意typename只被用来验明嵌套从属类型名称;其他名称不该有它存在。如下面的例子:

template<typename C>

void f(const C& container,typename C::iterator iter)。参数中第一个不是嵌套从属类型名称,所以不需要关键字typename,而第二个需要。

“typename必须作为嵌套从属类型名称的前缀词”这一规则的例外是,typename不可以出现在base classes list内的嵌套从属类型名称之前,也不可在member initalization list(成员初始列)中作为base class修饰符。例如:

template<typename T>
class Derived:public Base<T>::Nested      //base list中不允许"typename"
{
public:
 explicit Derived(int x)
  :Base<T>::Nested(x)                //mem init list中不允许有"typename"
 {
  typename Base<T>::Nested temp;     //这个一定要有"typename"
 }
}

最后声明一点:以上讲的在VC++ 6.0下不适用,也就是说在VC下不用typename修饰嵌套从属类型,编译器也不会抱怨,但是在gcc内核下就会发生抱怨。

参考文献:《Effective C++》

Typename和Class在声明模板时的区别相关推荐

  1. Vue里标签嵌套限制问题解决------解析DOM模板时注意事项:

    Vue里标签嵌套限制问题解决------解析DOM模板时注意事项: 参考文章: (1)Vue里标签嵌套限制问题解决------解析DOM模板时注意事项: (2)https://www.cnblogs. ...

  2. java 定义变量时 赋值与不赋值_探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值...

    探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值 当基本数据类型作为普通变量(八大基本类型: byte,char,boolean,short,int,long,fl ...

  3. warning C4091: “typedef ”: 没有声明变量时忽略“_matcher”的左侧

    C++ 警告  warning C4091: "typedef ": 没有声明变量时忽略"_matcher"的左侧 typedef struct _matche ...

  4. [react] 在React中声明组件时组件名的第一个字母必须是大写吗?为什么?

    [react] 在React中声明组件时组件名的第一个字母必须是大写吗?为什么? 必须,React根据首字母是否大写来区分react组件还是dom元素 个人简介 我是歌谣,欢迎和大家一起交流前后端知识 ...

  5. [vue]vue渲染模板时怎么保留模板中的HTML注释呢?

    [vue]vue渲染模板时怎么保留模板中的HTML注释呢? <template comments>... </template> 个人简介 我是歌谣,欢迎和大家一起交流前后端知 ...

  6. RabbitMQ 声明Queue时的参数们的Power

    RabbitMQ 声明Queue时的参数们的Power 参数们的Power 在声明队列的时候会有很多的参数 public static QueueDeclareOk QueueDeclare(this ...

  7. html使用thymeleaf模板时,获取数据库中字符串值,拆分为list根据下标获取对应的值的方法

    1. 需求 html使用thymeleaf模板时,获取数据库中字符串值,拆分为list根据下标获取对应的值的方法 2. 方法 2.1 参考官网:https://www.thymeleaf.org/do ...

  8. 下载、安装Ctex及编译自动化学报模板时错误的解决

    一.下载 直接在清华源下载 https://mirrors.tuna.tsinghua.edu.cn/ctex/legacy/2.9/ 选择 二.安装 安装一般直接都下一步就行,可以自己修改安装路径, ...

  9. java 基本类型 不赋值_探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值...

    探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值 当基本数据类型作为普通变量(八大基本类型: byte,char,boolean,short,int,long,fl ...

最新文章

  1. 五个运动员参加比赛根据他们说的话判断结果
  2. HTTP权威指南记录 ---- HTTP概述
  3. 钟国晨 160809323
  4. 【Git】GitHub主页从Dark调回Light的方法
  5. python中while的用法_Python学习笔记之While循环用法分析
  6. pythonkeywordis与 ==的差别
  7. [转载]表的设计命名的十个注意点
  8. C系新版凯立德推荐版本G1036
  9. 使用 DiskMaker X 轻松制作 Yosemite 安装 U 盘(引)
  10. 信息可视化中的重要准则——以扇贝单词app中的可视化为例
  11. python 爬虫3 新浪微博 爬虫 实战
  12. 揭开LiteOS的神秘面纱
  13. 成功解决 ValueError: Not a TBLoader or TBPlugin subclass: <class ‘tensorboard_plugin_wit.wit_plugin_load
  14. 为什么Linkerd不使用Envoy
  15. c语言间隔符号的作用,C语言教学(二)常见的符号
  16. html中微博发布怎么做,js实现微博发布小功能
  17. java中gui_java中GUI是什么意思?详细图解
  18. 10-221 在员工表中查询入职最晚的员工的编号,姓名和入职日期
  19. USB无线网卡和PCI-E无线网卡
  20. java 读取手机文件_Android获取手机文件夹及文件列表的方法

热门文章

  1. IEEE JBHI 投稿因格式问题打回记录
  2. 分享java web 期末项目实验源码20套,BBS论坛,ERP管理系统,OA自动化等等
  3. Mysql查询语句练习题
  4. Oracle DBA课程系列笔记(4)
  5. [视频]Silverlight for Windows Phone 7基本开发过程以及Push Button控件的使用
  6. ruby require
  7. 深入浅出三剑客之awk必杀技一例
  8. MySQL--禁用账号和设置账号有效期
  9. flask-limiter限制单个IP访问的频率和次数
  10. 控件必须放在具有 runat=server 的窗体标记内错误的解决方法