c++11-17 模板核心知识(十五)—— 解析模板之依赖型类型名称与typename Dependent Names of Types
上篇文章c++11-17 模板核心知识(十四)—— 解析模板之依赖型模板名称 Dependent Names of Templates(.template/->template/::template) 介绍了依赖型模板名称,提到关于模板解析有六个大方面:
- 非模板中的上下文相关性 Context Sensitivity in Nontemplates
- 依赖型类型名称 Dependent Names of Types <-----
- 依赖型模板名称 Dependent Names of Templates
- using-declaration中的依赖型名称 Dependent Names in Using Declarations
- ADL和显式模板实参 ADL and Explicit Template Arguments
- 依赖性表达式 Dependent Expressions
这篇文章介绍下依赖型类型名称(Dependent Names of Types)。
模板名称的问题及解决
模板中的名称存在一个问题:它们有的时候不能被很好的分类,比如一个模板引用其他模板的名称,因为模板特化的存在,会让问题变得复杂一些。例如:
template <typename T> class Trap {
public:
enum { x }; // #1 x is not a type here
};
template <typename T> class Victim {
public:
int y;
void poof() {
Trap<T>::x *y; // #2 declaration or multiplication?
}
};
template <> class Trap<void> { // evil specialization!
public:
using x = int; // #3 x is a type here
};
void boom(Victim<void> &bomb) { bomb.poof(); }
如果你直接编译,会报错:
main.cc:30:14: error: unexpected type name 'x': expected expression
Trap<T>::x *y; // #2 declaration or multiplication?
^
main.cc:39:38: note: in instantiation of member function 'Victim<void>::poof' requested here
void boom(Victim<void> &bomb) { bomb.poof(); }
^
1 error generated.
这个问题和解决方案在c++11-17 模板核心知识(二)—— 类模板涉及过,这篇文章再展开说一下相关规则。
回到上面的例子,当编译器解析到#2处时,它需要决定Trap<T>::x是一个类型还是一个值,这决定了Trap<T>::x *y是声明一个指针还是做乘法。
问题是,在Trap中,Trap<T>::x是一个值,但是在全特化版本Trap<void>中,Trap<T>::x是一个类型。所以,这种情况实际是依赖模板参数T的,也就是依赖型类型名称(Dependent Names of Types)。
C++规定,只有当加上typename关键字后,依赖型类型名称才会被当做类型,否则会被当做一个值。这里typename的意义和声明一个模板时使用的typename是两个意思,所以不能用class来替换typename.
typename规则
当一个名称具备以下性质时,需要在名称前面加typename:
- 是qualified name。
- 不是Elaborated type specifier的一部分(例如,以class、struct、union、enum为开头的类型)
- 名称不是用于指定基类继承的列表中,也不是位于引入构造函数的成员初始化列表中。
- 依赖于模板参数。
例如:
template <typename(1) T>
struct S : typename(2) X<T>::Base {
S() : typename(3) X<T>::Base(typename(4) X<T>::Base(0)) {}
typename(5) X<T> f() {
typename(6) X<T>::C *p; // declaration of pointer p
X<T>::D *q; // multiplication!
}
typename(7) X<int>::C *s;
using Type = T;
using OtherType = typename(8) S<T>::Type;
};
下面逐一说下上面各个typename的使用场景(有的使用方式是错误的):
- 第一个typename代表一个模板参数,不在此文章讨论范围内。
- 第二和第三个typename是错误的使用方式,不需要添加,违反了上面的第3条规则。第二个出现在了指定基类继承的列表中,第三个出现在了构造函数的成员初始化列表。如果加上typename编译,会报如下错误:
main.cc:30:12: error: 'typename' is redundant; base classes are implicitly types
struct S : typename X<T>::Base {
^~~~~~~~~
- 第四个typename是必须的,它满足上面第3条规则,且其他规则也满足。
- 第五个typename是错误的,因为X不是一个qualified name,如果加上typename编译,会报:
main.cc:33:12: error: expected a qualified name after 'typename'
typename X<T> f() {
^
- 第六个typename是必须的,上面讲过,代表一个类型。
- 第七个typename是可有可无的,因为
X<int>::C不依赖模板参数,即不是Dependent Name. - 第八个typename也是可有可无的,因为它指向的是
current instantiation,这个概念下篇文章会讲到。
C++20 typename
是了,这一大堆乱七八糟的规则,谁也不想去记。C++20对typename的规则做了一些改善,有一些场景不再需要typename。详情大家可以参考 : The typename disambiguator for dependent names

(完)
朋友们可以关注下我的公众号,获得最及时的更新:

c++11-17 模板核心知识(十五)—— 解析模板之依赖型类型名称与typename Dependent Names of Types的更多相关文章
- c++11-17 模板核心知识(五)—— 理解模板参数推导规则
Case 1 : ParamType是一个指针或者引用,但不是universal reference T& const T& T* Case 2 : ParamType是Univers ...
- c++11-17 模板核心知识(十一)—— 编写泛型库需要的基本技术
Callables 函数对象 Function Objects 处理成员函数及额外的参数 std::invoke<>() 统一包装 泛型库的其他基本技术 Type Traits std:: ...
- c++11-17 模板核心知识(十二)—— 模板的模板参数 Template Template Parameters
概念 举例 模板的模板参数的参数匹配 Template Template Argument Matching 解决办法一 解决办法二 概念 一个模板的参数是模板类型. 举例 在c++11-17 模板核 ...
- c++11-17 模板核心知识(十四)—— 解析模板之依赖型模板名称(.template/->template/::template)
tokenization与parsing 解析模板之类型的依赖名称 Dependent Names of Templates Example One Example Two Example Three ...
- c++11-17 模板核心知识(二)—— 类模板
类模板声明.实现与使用 Class Instantiation 使用类模板的部分成员函数 Concept 友元 方式一 方式二 类模板的全特化 类模板的偏特化 多模板参数的偏特化 默认模板参数 Typ ...
- c++11-17 模板核心知识(一)—— 函数模板
1.1 定义函数模板 1.2 使用函数模板 1.3 两阶段翻译 Two-Phase Translation 1.3.1 模板的编译和链接问题 1.4 多模板参数 1.4.1 引入额外模板参数作为返回值 ...
- Django(十五)模板详解:模板标签、过滤器、模板注释、模板继承、html转义
一.模板的基础配置及使用 [参考]https://docs.djangoproject.com/zh-hans/3.0/topics/templates/ 作为Web框架,Django提供了模板,用于 ...
- c++11-17 模板核心知识(十三)—— 名称查找与ADL
名称分类 名称查找 ordinary lookup ADL (Argument-Dependent Lookup) 官网的例子 ADL的缺点 在C++中,如果编译器遇到一个名称,它会寻找这个名称代表什 ...
- c++11-17 模板核心知识(十)—— 区分万能引用(universal references)和右值引用
引子 如何区分 模板参数 const disqualify universal reference auto声明 引子 T&&在代码里并不总是右值引用: void f(Widget&a ...
随机推荐
- CSS 三栏自适应布局
CSS布局 这个很基础,方法也很多,要留意的知识点还是有一些. 比如IE6的触发layout *zoom:1 比如使用浮动后的清除浮动 clear:both 需求的延伸也会有一些: 比如三栏等高 ...
- nginx&http 第三章 ngx 1-http ngx_http_wait_request_handler
对于活跃的 HTTP 连接,在执行连接建立回调函数 ngx_http_init_connection 的过程中会执行 ngx_http_wait_request_handler 回调函数, 负责 HT ...
- tcp 接收被动关闭 fin
void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th, unsigned int ...
- Windows查找JDK的路径
第一步:确定是否安装JDK 在控制台输入: java -version 此时说明你电脑安装了JDK. 第二步:查找路径 然后在控制台输入: java -verbose 输出结果: 最后两行就是相应的j ...
- HttpClient4.3 连接池参数配置及源码解读
目前所在公司使用HttpClient 4.3.3版本发送Rest请求,调用接口.最近出现了调用查询接口服务慢的生产问题,在排查整个调用链可能存在的问题时(从客户端发起Http请求->ESB-&g ...
- 重闯Sqli-labs关卡第一天(1-4关)
前言 之前暑假闯了很多关但是最近刷BUGku的题 遇到SQL注入题就凉... 垃圾的我只能继续硬着头皮重新再来学习,再来闯. 第一关:字符型注入 字符型注入就是注入点的数据类型是字符型.字符型注入与数 ...
- bWAPP----HTML Injection - Reflected (POST)
bWAPP--low--HTML Injection - Reflected (POST) 只不过是把传递方式换成post, 防护的三个级别和内容与GET相同 1 function htmli($da ...
- mysql 重要日志文件总结
作者:丁仪 来源:https://chengxuzhixin.com/blog/post/mysql_zhong_yao_ri_zhi_wen_jian_zong_jie.html 日志是所有应用的重 ...
- Redis 用的很溜,了解过它用的什么协议吗?
我是风筝,公众号「古时的风筝」,一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在 ...
- EasyRecovery——信息时代的“后悔药”
前几日,小编在豆瓣潜水的时候看到这么一个帖子,说是一对小情侣吵架,女方一气之下把男方的博士论文和资料全删了,求一个办法让男友消气. 站在吃瓜的角度,小编和广大群众看法一致,希望两人直接分手,放男方一条 ...