上篇文章c++11-17 模板核心知识(十四)—— 解析模板之依赖型模板名称 Dependent Names of Templates(.template/->template/::template) 介绍了依赖型模板名称,提到关于模板解析有六个大方面:c++
这篇文章介绍下依赖型类型名称(Dependent Names of Types)。git
模板中的名称存在一个问题:它们有的时候不能被很好的分类,好比一个模板引用其余模板的名称,由于模板特化的存在,会让问题变得复杂一些。例如:github
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(); }
若是你直接编译,会报错:express
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++11
C++规定,只有当加上typename关键字后,依赖型类型名称才会被当作类型,不然会被当作一个值。这里typename的意义和声明一个模板时使用的typename是两个意思,因此不能用class来替换typename.code
当一个名称具有如下性质时,须要在名称前面加typename:blog
例如:继承
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的使用场景(有的使用方式是错误的):
main.cc:30:12: error: 'typename' is redundant; base classes are implicitly types struct S : typename X<T>::Base { ^~~~~~~~~
main.cc:33:12: error: expected a qualified name after 'typename' typename X<T> f() { ^
X<int>::C
不依赖模板参数,即不是Dependent Name.current instantiation
,这个概念下篇文章会讲到。是了,这一大堆乱七八糟的规则,谁也不想去记。C++20对typename的规则作了一些改善,有一些场景再也不须要typename。详情你们能够参考 : The typename disambiguator for dependent names
(完)
朋友们能够关注下个人公众号,得到最及时的更新: