c++11-17 模板核心知识(十四)—— 解析模板之依赖型模板名称 Dependent Names of Templates(.template/->template/::template)
- tokenization与parsing
- 解析模板之类型的依赖名称 Dependent Names of Templates Example One
- Example Two
- Example Three
有时间的建议先看下上篇文章 : c++11-17 模板核心知识(十三)—— 名称查找与ADL
tokenization与parsing
绝大多数语言在编译的时候都有两个阶段:
- tokenization,或者叫scanning/lexing
- parsing
tokenization阶段会读取源码并生成一系列token. 例如:
int *p = 0;,tokenizer会生成关键字int、运算符*、标识符p、运算符=、整数0、运算符;
接下来,parser会递归的减少标记,寻找已知的模式。例如:token 0是一个合法的表达式,*p组合也是一个合法的声明,它和后面的=0组合也是一个合法初始化声明。最后,int是一个已知的类型,后面跟着初始化声明 : *p=0,所以,我们得到了一个初始化p的声明
解析模板之类型的依赖名称 Dependent Names of Templates
关于模板解析有六个大方面:
- 非模板中的上下文相关性 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 Templates)
这里有一个很重要的概念 : 在c++11-17 模板核心知识(十三)—— 名称查找与ADL中介绍过的Dependent Name:依赖于模板参数的名称,也就是访问运算符左面的表达式类型依赖于模板参数。例如:std::vector::iterator是一个 Dependent Name,但假如T是一个已知类型的别名(using T = int),那就不是Dependent Name。
通常而言, 编译器会把模板名称后面的<当做模板参数列表的开始,否则,<就是比较运算符。但是,当引用的模板名称是Dependent Name时,编译器不会假定它是一个模板名称,除非显示的使用template关键字来指明,模板代码中常见的
->template、
.template、
::template就应用于这种场景中。
下面看几个例子。
Example One
template<unsigned long N> void printBitset (std::bitset<N> const& bs) { std::cout << bs.template to_string<char, std::char_traits<char>, std::allocator<char>>(); }
这里,参数bs依赖于模板参数N。所以,我们必须通过template关键字让编译器知道bs是一个模板名称,否则按照上面的规则,
<会被当做比较符——小于号。
Example Two
The template keyword as qualifier (C++ only)中的例子:
#include <iostream> using namespace std; class X { public: template <int j> struct S { void h() { cout << "member template's member function: " << j << endl; } }; template <int i> void f() { cout << "Primary: " << i << endl; } }; template<> void X::f<20>() { cout << "Specialized, non-type argument = 20" << endl; } template<class T> void g(T* p) { p->template f<100>(); p->template f<20>(); typename T::template S<40> s; // use of scope operator on a member template s.h(); } int main() { X temp; g(&temp); }
这里,参数p依赖模板参数T。注意
typename T::template S<40> s;的使用。
Example Three
template <typename T> class Shell { public: template <int N> class In { public: template <int M> class Deep { public: virtual void f(); }; }; }; template <typename T, int N> class Weird { public: void case1(typename Shell<T>::template In<N>::template Deep<N> *p) { p->template Deep<N>::f(); // inhibit virtual call } void case2(typename Shell<T>::template In<N>::template Deep<N> &p) { p.template Deep<N>::f(); // inhibit virtual call } };
参数p依赖模板参数T。编译器不会去判断
p.Deep是不是模板。如果不指定template,那么
p.Deep<N>::f()就会被解析成
((p.Deep)<N)>f();,
<被当做比较符。
基于上面的例子,我们也可以知道,
->template、
.template、
::template只存在于模板中,并且是在Dependent Name的场景下使用(依赖于模板参数)。
(完)
朋友们可以关注下我的公众号,获得最及时的更新:
- c++11-17 模板核心知识(十五)—— 解析模板之依赖型类型名称与typename Dependent Names of Types
- c++11-17 模板核心知识(十二)—— 模板的模板参数 Template Template Parameters
- c++11-17 模板核心知识(三)—— 非类型模板参数 Nontype Template Parameters
- c++11-17 模板核心知识(八)—— enable_if<>与SFINAE
- c++11-17 模板核心知识(十)—— 区分万能引用(universal references)和右值引用
- c++11-17 模板核心知识(十一)—— 编写泛型库需要的基本技术
- c++11-17 模板核心知识(六)—— 理解auto推导规则
- C++Template——Names in templates(模板中的名称)
- c++11-17 模板核心知识(九)—— 理解decltype与decltype(auto)
- 【Web】<script type="text/template"></script>适合用于定义模板(模板容器),不解析(渲染/执行)
- XSL学习笔记2 XSLT的模板规则<xsl:template>和<xsl:apply-templates>
- Easy Way to Get All Dependent Library Names 快速获得所有依赖库名称
- 强大的DataGrid组件[9]_自定义头模板(HeaderTemplate)——Silverlight学习笔记[17]
- C++11: default template arguments for both function and class templates
- 常用知识总结——模板Template
- 设计模式(十四)模板方法模式(Template Pattern)
- [c++][template]模板基础知识
- Admin管理后台模板 Free HTML Admin Templates For The Backend Of Your Apps
- C++类模板 template <class T>
- playbook核心元素之 模板template 介绍(7)