- 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
通常而言, 編譯器會把模板名稱后面的<當做模板引數串列的開始,否則,<就是比較運算子,但是,當參考的模板名稱是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的場景下使用(依賴于模板引數),
(完)
朋友們可以關注下我的公眾號,獲得最及時的更新:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/231712.html
標籤:C++
上一篇:【C/C++】C和C++11之enum列舉的使用細節
下一篇:c++prime筆記八、 IO
