c++11-17 模板核心知识(十五)—— 解析模板之依赖型类型名称与typename Dependent Names of Types
2020-12-08 23:22
1801 查看
上篇文章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为开头的类型)
- 名称不是用于指定基类继承的列表 56c 中,也不是位于引入构造函数的成员初始化列表中。
- 依赖于模板参数。
例如:
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条规则,且其他规则也满足。
- 第 ad8 五个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 模板核心知识(三)—— 非类型模板参数 Nontype Template Parameters
- c++11-17 模板核心知识(九)—— 理解decltype与decltype(auto)
- c++11-17 模板核心知识(十)—— 区分万能引用(universal references)和右值引用
- c++11-17 模板核心知识(十一)—— 编写泛型库需要的基本技术
- c++11-17 模板核心知识(六)—— 理解auto推导规则
- c++11-17 模板核心知识(十二)—— 模板的模板参数 Template Template Parameters
- c++11-17 模板核心知识(八)—— enable_if<>与SFINAE
- 使用 PropTypes 进行类型检 || 控制台报:TypeError: Cannot read property 'string' of undefined)
- 两个类具有相同的 XML 类型名称。请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。
- Effective C++第七章-模板和泛型编程之typename与嵌套从属名称
- Invalid ADAPTORNAME specified. Type 'imaqhwinfo' for a list of available ADAPTORNAMEs. Image acquisi
- httppost的用法(NameValuePair(简单名称值对节点类型)核心对象)
- 值类型与引用类型(特殊的string) Typeof和GetType() 静态和非静态使用 参数传递 相关知识
- 类型名称后面的括号是否与new有所不同? - Do the parentheses after the type name make a difference with new?
- 用模板template<typename T>实现int double等类型转string
- 用模板template<typename T>实现int double等类型转string
- 用模板template<typename T>实现int double等类型转string
- 黑马程序员--Java基础加强--17.利用反射操作泛型VI【泛型类型变量的语义】【GenericDeclaration接口】【泛型接口TypeVariable】【通过Class反射解析泛型类】
- 用模板template<typename T>实现int double等类型转string
- JavaScript DOM杂知识(value/innerHTML/innerText/textContent对比、nodeType/nodeName/nodeValue区别、获取任意类型的属性)