一、引入 变量模板是在 C++14 中引入,允许在命名空间范围内定义模板变量(可以表示一组全局变量),或者在类范围内定义模板变量(表示静态数据成员)。
例如:
1 2 template <class T > constexpr T PI = T (3 ,1415926535897932385L );
其语法类似于声明变量(或数据成员),但与声明模板的语法相结合。
对于任何模板,该声明不能出现在函数内或者块区域内。
使用变量模板,必须指定它的类型:
1 2 std::cout << PI<double > << '\n' ; std::cout << PI<float > << '\n' ;
二、应用 2.1 简单使用 可以声明在不同编译单元中使用的变量模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 template <typename T> T val{}; #include "header.hpp" int main () { val<long > = 42 ; print (); }#include "header.hpp" void print () { std::cout << val<long > << '\n' ; }
2.2 变量模板的显式特化 函数模板 show_parts 会将输入字符串分割为用分隔符分隔的部分后处理。分隔符是在(全局) 命名空间范围内定义的变量模板,并且为 wchar_t 类型显式特化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 template <typename T>constexpr T SEPARATOR = '\n' ;template <>constexpr wchar_t SEPARATOR<wchar_t > = L'\n' ;template <typename T>std::basic_ostream<T>& show_parts ( std::basic_ostream<T>& s, std::basic_string_view<T> const & str) { using size_type = typename std::basic_string_view<T>::size_type; size_type start = 0 ; size_type end; do { end = str.find (SEPARATOR<T>, start); s << '[' << str.substr (start, end - start) << ']' << SEPARATOR<T>; start = end + 1 ; } while (end != std::string::npos); return s; }show_parts <char >(std::cout, "one\ntwo\nthree" );show_parts <wchar_t >(std::wcout, L"one line" );
2.3 变量模板作为成员变量 变量模板可以是类的成员,可表示静态数据成员,需要使用 static 关键字进行声明:
1 2 3 4 5 6 7 8 9 10 11 struct math_constants { template <class T > static constexpr T PI = T (3.1415926535897932385L ); };template <typename T>T sphere_volume (T const r) { return 4 * math_constants::PI<T> *r * r * r / 3 ; }
可以在类中声明一个变量模板,然后在类外提供它的定义。注意,变量模板必须声明为静态 const,而不是静态constexpr,因为后者需要在类内初始化:
1 2 3 4 5 6 7 8 struct math_constants { template <class T > static constexpr T PI; };template <class T >const T math_constants::PI = T (3.1415926535897932385L );
2.4 简化类型特征 以 is_integral 为例:
1 2 3 4 5 6 7 template <typename T>struct is_integral { constexpr static bool value = false ; } std::cout << is_integral<float >::value << '\n' ;
可以通过如下定义的变量模板来简化:
1 2 3 4 5 template <typename T>inline constexpr boool is_integral_v = is_integral<T>::value; std::cout << is_floating_point_v<float > << '\n' ;