C++基礎::變數模板(variable template)
既然允許C++模板類(class template)的存在,允許C++函式模板(function template)的存在,也應當允許變數模板(variable template)的存在。
引入
變數模板,標準C++14(C++11是C++14的一個subset子集,)的一個新的語法特性。C++新標準引入變數模板的主要目的是為了簡化定義(simplify definitions)以及對模板化常量(parameterized constant)的支援。
C++14之前的語法規則不允許使用模板宣告的方式宣告一個變數
template<typename T>
T var; // not allowed in pre-C++14
var<int> = 5; // == (int var = 5;)
它足夠新,以至於相當多的編譯器還未完全支援,比如windows下的vs2013。本文涉及的程式碼統一在C++的一個線上ide——ideone中進行編譯(選擇這個編譯器的目的主要在於它對C++14標準的支援)。
線上編譯器c++標準可選
條條大陸通羅馬,此路不通(C++14標準之前),我們雖然有一些另外的替代方案,但這些方案,往往冗餘度過高且形式比較複雜。
workaround 1
第一種替代方案是,使用類别範本的constexpr static
資料成員的方式:
template<typename T>
struct PI
{
constexpr static T pi = T(3.1415926535897932385);
// 這裡必須使用關鍵字constexpr,而不可以是const
// const 常量必須在編譯器得到確定
// 自C++11起,constexpr可以讓表示式核定於編譯期
}
// duplicate declaration
template<typename T>
constexpr T PI<T>::pi;
int main(int, char**)
{
std::cout << PI<int>::pi << std::endl;
// 3
std::cout << PI<double>::pi << std::endl;
// 3.14159
return 0;
}
這種做法,因為constant
是一種ODR(One Definition Rule)
的定義規則。對constant的兩次宣告是有必要的,一次在類别範本體內,一次在類别範本體外,如上程式碼所示。
workaround 2
另外一種解決方案是使用constexpr
函式模板的形式,該函式返回期待的型別。
template<typename T>
T PI()
{
constexpr T pi = T(3.1415926535897932385);
return pi;
}
int main(int, char**)
{
std::cout << PI<int>() << std::endl;
std::cout << PI<double>() << std::endl;
return 0;
}
variable template
現在,有了C++新標準對變數模板的支援,操縱一個可變型別的常量可以得到顯著的簡化,
// old version
PI<int>::pi // constexpr static data member
PI<int>() // constexpr function
// new version
PI<int>
template<typename T>
constexpr T PI = T(3.1415926535897932385);
template<typename T>
T area(T r)
{
return PI<T>*r*r;
}
int main(int, char**)
{
std::cout << PI<int> << std::endl;
std::cout << area(2.0) << std::endl;
// 函式模板的自動型別推導
return 0;
}
當然我們亦可以將變數模板應用到一個非常量變數上來;
tempalte<typename T>
T val = T(3.1415926535897932385);
int main(int, char**)
{
val<float> = 0.6180339887498948482;
std::cout << val<float> << std::endl;
// 使用新賦的值
std::cout << val<double> << std::endl;
// 使用預設值
return 0;
}
References
相關文章
- c++ 模板模板引數("Template Template Parameters")C++
- c++基礎三(變數)C++變數
- C++開發:template,模板C++
- 【ES6基礎】模板字串(Template String)字串
- c++可變模板引數C++
- C++程式設計基礎(2)變數C++程式設計變數
- c++11-17 模板核心知識(十二)—— 模板的模板引數 Template Template ParametersC++
- Python基礎:變數Python變數
- python變數基礎Python變數
- C++ 可變引數模板遞迴展開C++遞迴
- C++反射機制:可變引數模板實現C++反射C++反射
- 模板方法模式(Template)模式
- Python:Template模板字串Python字串
- JavaScript基礎(二)變數JavaScript變數
- python_基礎_變數Python變數
- [java基礎]之變數Java變數
- C++反射機制:可變引數模板實現C++反射薦C++反射
- C++反射機制:可變引數模板實現C++反射(二)C++反射
- c++11-17 模板核心知識(十四)—— 解析模板之依賴型模板名稱 Dependent Names of Templates(.template/->template/::template)C++
- Java基礎-基礎語法-變數與常量Java變數
- C++之templateC++
- PHP->GO 基礎-變數PHPGo變數
- WPF 資料模板Data Template
- Js基礎知識(一) – 變數JS變數
- Go基礎系列:常量和變數Go變數
- 基礎 變數的作用範圍變數
- python基礎學習_01變數Python變數
- java基礎變數的交換Java變數
- CSS基礎:CSS變數簡介CSS變數
- Linux基礎之Shell與變數Linux變數
- JAVA基礎04——變數與常量Java變數
- 基礎莫隊模板
- c++基礎C++
- Go HTML/template 模板使用方法GoHTML
- TypeScript基礎入門-變數宣告(一)TypeScript變數
- 基礎的python知識2 (變數)Python變數
- Javascript基礎:變數型別轉換JavaScript變數型別
- Java基礎06:變數、常量、作用域Java變數
- python極簡教程01:基礎變數Python變數