Переменные-шаблоны (variable templates)
Вольный перевод гл.5.6.
Да, мы имеем очень похожие термины для очень разных вещей: Переменная-шаблон (variable template) это переменная, которая является шаблоном ("переменная" здесь существительное). Вариативный шаблон (variadic template) - это шаблон с вариативным числом шаблонных параметров ("вариативный" здесь прилагательное).
Начиная с С++14, переменные могут быть параметризированы для специфического типа. Такая вещь и называется переменной-шаблоном.
Например, мы можем определить значение числа 'пи' не определяя типа этого значения.
template<typename T>constexpr T pi{3.1415926535897932385};
Как и для всех шаблонов это объявление не может находиться внутри функции или блока видимости.
Чтобы использовать переменную-шаблон, мы должны специфицировать её тип.
Например, ниже используются две различные переменные в области видимости, в которой объявлено pi<>.
std::cout << pi<double> << ’\n’;
std::cout << pi<float> << ’\n’;
Можно объявлять переменные-шаблоны, которые используются в различных единицах трансляции:
//== header.hpp:
template<typename T> T val{}; // zero initialized value
//== translation unit 1:
#include "header.hpp"
int main()
{
val<long> = 42;
print();
}
//== translation unit 2:
#include "header.hpp"
void print()
{
std::cout << val<long> << ’\n’; // OK: prints 42
}
Переменные-шаблоны могут иметь шаблонные аргументы по умолчанию:
template<typename T = long double>constexpr T pi = T{3.1415926535897932385};
При использовании надо всегда указывать угловые скобки:
std::cout << pi << ’\n’; //ERROR
Переменные-шаблоны могут быть параметризированы нетиповыми параметрами, которые также могут быть использованы, чтобы параметризировать инициализатор. Например
template<auto N>
constexpr decltype(N) dval = N; // тип dval зависит от переданной величины
int main()
{
std::cout << dval<'c'> << '\n'; // N имеет величину ’c’ типа char
}
Переменные-шаблоны для членов данных.
Полезное применение для переменных-шаблонов заключается в определении переменных-членов шаблонного класса. Например, если шаблонный класс определен так:
template<typename T>class MyClass { public: static constexpr int max = 1000;
};
то вы можете определить
template<typename T>int myMax = MyClass<T>::max;
поэтому прикладной программист может просто написать
auto i = myMax<std::string>;
вместо
auto i = MyClass<std::string>::max;
Это означает, что для класса стандартной библиотеки
namespace std
{ template<typename T> class numeric_limits { public:
…
static constexpr bool is_signed = false;
…
};
}
вы можете определить
template<typename T>constexpr bool isSigned = std::numeric_limits<T>::is_signed;
чтобы иметь возможность написать
isSigned<char>
вместо
std::numeric_limits<char>::is_signed .
Суффикс характеристик типов _v
Начиная с С++17, стандартная библиотека использует технику переменных-шаблонов для определения коротких имен для всех характеристик типов в STL, которые имеют булевское значение, например, теперь можно писать
std::is_const_v<T> // since C++17
вместо
std::is_const<T>::value //since C++11
Да, мы имеем очень похожие термины для очень разных вещей: Переменная-шаблон (variable template) это переменная, которая является шаблоном ("переменная" здесь существительное). Вариативный шаблон (variadic template) - это шаблон с вариативным числом шаблонных параметров ("вариативный" здесь прилагательное).
Начиная с С++14, переменные могут быть параметризированы для специфического типа. Такая вещь и называется переменной-шаблоном.
Например, мы можем определить значение числа 'пи' не определяя типа этого значения.
template<typename T>constexpr T pi{3.1415926535897932385};
Как и для всех шаблонов это объявление не может находиться внутри функции или блока видимости.
Чтобы использовать переменную-шаблон, мы должны специфицировать её тип.
Например, ниже используются две различные переменные в области видимости, в которой объявлено pi<>.
std::cout << pi<double> << ’\n’;
std::cout << pi<float> << ’\n’;
Можно объявлять переменные-шаблоны, которые используются в различных единицах трансляции:
//== header.hpp:
template<typename T> T val{}; // zero initialized value
//== translation unit 1:
#include "header.hpp"
int main()
{
val<long> = 42;
print();
}
//== translation unit 2:
#include "header.hpp"
void print()
{
std::cout << val<long> << ’\n’; // OK: prints 42
}
Переменные-шаблоны могут иметь шаблонные аргументы по умолчанию:
template<typename T = long double>constexpr T pi = T{3.1415926535897932385};
При использовании надо всегда указывать угловые скобки:
std::cout << pi << ’\n’; //ERROR
Переменные-шаблоны могут быть параметризированы нетиповыми параметрами, которые также могут быть использованы, чтобы параметризировать инициализатор. Например
template<auto N>
constexpr decltype(N) dval = N; // тип dval зависит от переданной величины
int main()
{
std::cout << dval<'c'> << '\n'; // N имеет величину ’c’ типа char
}
Переменные-шаблоны для членов данных.
Полезное применение для переменных-шаблонов заключается в определении переменных-членов шаблонного класса. Например, если шаблонный класс определен так:
template<typename T>class MyClass { public: static constexpr int max = 1000;
};
то вы можете определить
template<typename T>int myMax = MyClass<T>::max;
поэтому прикладной программист может просто написать
auto i = myMax<std::string>;
вместо
auto i = MyClass<std::string>::max;
Это означает, что для класса стандартной библиотеки
namespace std
{ template<typename T> class numeric_limits { public:
…
static constexpr bool is_signed = false;
…
};
}
вы можете определить
template<typename T>constexpr bool isSigned = std::numeric_limits<T>::is_signed;
чтобы иметь возможность написать
isSigned<char>
вместо
std::numeric_limits<char>::is_signed .
Суффикс характеристик типов _v
Начиная с С++17, стандартная библиотека использует технику переменных-шаблонов для определения коротких имен для всех характеристик типов в STL, которые имеют булевское значение, например, теперь можно писать
std::is_const_v<T> // since C++17
вместо
std::is_const<T>::value //since C++11
Комментарии
Отправить комментарий