Language Feature | Proposal | Available in GCC? | SD-6 Feature Test |
Variable templates | N3651 | 5 | __cpp_variable_templates >= 201304 |
变量模板定义一族变量或静态数据成员。
语法:template < 形参列表 > 变量声明
- 变量声明 - 变量的声明。声明的变量名成为模板名。
- 形参列表 - 非空的模板形参的逗号分隔列表,每项是非类型形参、类型形参、模板形参,或任何上述的形参包之一。
C++新标准引入变量模板的主要目的是为了简化定义(simplify definitions)以及对模板化常量(parameterized constant)的支持。
C++14之前的语法规则不允许使用模板声明的方式声明一个变量。对于这个问题,有一些众所周知的变通方法:
- 使用类模板的constexpr静态数据成员
- 使用constexpr函数模板返回所需的值
变量模板可以由处于命名空间作用域中的模板声明引入,其中 声明 声明一个变量
#include <iostream> template<class T> constexpr T pi = T); // 变量模板 template<class T> T circular_area(T r) // 函数模板 { return pi<T> * r * r; // pi<T> 是变量模板实例化 } int main(int argc, char* argv[]) { std::cout << pi<int> << std::endl; std::cout << pi<float> << std::endl; std::cout << pi<double> << std::endl; std::cout << circular_area<double>) << std::endl; return 0; }
结果:
3 3.14159 3.14159 95.0332
在类作用域中使用时,变量模板声明一个静态数据成员模板
#include <iostream> struct limits { template<typename T> static const T min; // 静态数据成员模板的声明 }; template<typename T> const T limits::min = { 10 }; // 静态数据成员模板的定义 template<class T> struct X { static T s; // 类模板的非模板静态数据成员的声明 }; template<class T> T X<T>::s = 11; // 类模板的非模板静态数据成员的定义 int main(int argc, char* argv[]) { std::cout << limits::min<int> << std::endl; std::cout << X<int>::s << std::endl; return 0; }
结果:
10 11
变量模板应用到一个非常量变量上来
#include <iostream> template<typename T> T val = T); int main(int argc, char* argv[]) { val<float> = 0.68948482; std::cout << val<float> << std::endl; // 使用新赋的值 std::cout << val<double> << std::endl; // 使用默认值 return 0; }
结果:
g++ -std=c++14 -o n3651 n3651.cpp ./n3651 0.618034 3.14159
第一种替代方案是使用类模板的constexpr static数据成员的方式
#include <iostream> template<typename T> struct PI { constexpr static T pi = T); }; // duplicate declaration template<typename T> constexpr T PI<T>::pi; template<class T> T circular_area(T r) // 函数模板 { return PI<T>::pi * r * r; // pi<T> 是变量模板实例化 } int main(int argc, char* argv[]) { std::cout << PI<int>::pi << std::endl; std::cout << PI<float>::pi << std::endl; std::cout << PI<double>::pi << std::endl; std::cout << circular_area<double>) << std::endl; return 0; }
第二种替代方案是使用constexpr函数模板的形式,该函数返回期待的类型
#include <iostream> template<typename T> T PI() { constexpr T pi = T); return pi; } template<class T> T circular_area(T r) // 函数模板 { return PI<T>() * r * r; // pi<T> 是变量模板实例化 } int main(int argc, char* argv[]) { std::cout << PI<int>() << std::endl; std::cout << PI<float>() << std::endl; std::cout << PI<double>() << std::endl; std::cout << circular_area<double>) << std::endl; return 0; }