Последнее обновление:2026-10-12
Шаблоны переменных в C++17¶
C++那些事 — шаблоны переменных¶
При написании шаблонного кода нам часто требуется определять и использовать различные типовые признаки (type traits). Эти признаки обычно применяются для проверки типов на этапе компиляции; примерами служат предоставляемые STL std::is_const, std::is_same и std::is_reference. С их помощью разработчики могут принимать решения на этапе компиляции, опираясь на свойства типов.
В этой статье рассказывается, как использовать шаблоны переменных C++14 (variable templates) для упрощения написания типовых признаков, а также приводится простой пример.
C++11¶
В C++11 написание типовых признаков обычно требует использования struct или std::integral_constant для инкапсуляции логического значения. Например, чтобы написать типовой признак is_float, проверяющий, является ли тип float, можно реализовать его так:
template <typename T>
struct is_float {
static constexpr bool value = std::is_same<T, float>::value;
};
Или чуть лаконичнее — с помощью псевдонима типа и std::integral_constant:
Хотя это лаконичнее, чем использовать struct напрямую, в итоге мы всё равно определяем тип, а не получаем сразу логическое значение. Чтобы воспользоваться таким признаком, приходится получать логическое значение через член ::value:
template <typename T>
void test(T t){
if (is_float<T>::value){
std::cout << "I'm a float" << std::endl;
} else {
std::cout << "I'm not a float" << std::endl;
}
}
Это работает, но остаётся два недостатка:
1. При каждом использовании типового признака приходится обращаться к ::value.
2. При определении нового типового признака необходимо объявлять новый тип или псевдоним типа, что увеличивает избыточность кода.
Появление шаблонов переменных в C++14¶
В C++14 появились шаблоны переменных, позволяющие определять переменные, зависящие от типа, напрямую. Эта возможность упростила написание типовых признаков: нам больше не нужно использовать псевдонимы типов или struct для инкапсуляции логического значения — можно определить само логическое значение.
Признак is_float в переписанном виде выглядит так:
Такой способ выглядит более лаконичным и понятным, без лишнего кода. Использовать его тоже удобнее:
template <typename T>
void test(T t){
if (is_float<T>){
std::cout << "I'm a float" << std::endl;
} else {
std::cout << "I'm not a float" << std::endl;
}
}
По сравнению с прежним вариантом при использовании шаблонов переменных больше не нужно обращаться к логическому значению через ::value, код стал проще и нагляднее.
Преимущества шаблонов переменных¶
- Меньше избыточного кода: шаблоны переменных позволяют напрямую определять зависящие от типов переменные, избегая избыточного кода инкапсуляции логического значения в
structилиstd::integral_constant. - Лучшая читабельность: шаблоны переменных за счёт упрощения синтаксиса делают код яснее, особенно при написании большого числа типовых признаков.
- Поддержка специализации шаблонов: в отличие от шаблонов псевдонимов типов, шаблоны переменных можно специализировать — как полностью, так и частично. Мы можем определить отдельную логику для конкретных типов, не беспокоясь о расширяемости.
Дальнейшие улучшения в C++17¶
C++17 ещё больше расширил применение шаблонов переменных, предоставив для каждого типового признака вспомогательный шаблон переменной. Например, для std::is_same появился шаблон переменной std::is_same_v, упрощающий доступ к значению типового признака:
Благодаря этому использование типовых признаков стало ещё лаконичнее: разработчики могут напрямую применять шаблоны переменных, не обращаясь каждый раз к ::value.
Практический пример¶
Эта возможность широко используется на практике; например, при выделении блоков памяти разного размера в базе данных мы можем инициализировать размеры блоков разных типов с помощью шаблонов.
template <typename T>
constexpr size_t block_size = 1024; // 默认大小
template <>
constexpr size_t block_size<double> = 2048; // double 类型需要更多内存
Похожие темы¶
- Атрибут [[nodiscard]] в C++17 | C++那些事
- std::string_view в C++17 | C++那些事
- PMR-ресурсы памяти в C++17 | C++那些事
- Семнадцать расширенных возможностей C++17 | C++那些事
- Выведение аргументов шаблона класса CTAD в C++17 | C++那些事
- C++17 optional_ref | C++那些事
- std::variant в C++17 | C++那些事
- Структурированные привязки в C++17 | C++那些事
- Выведение auto в шаблонах C++17 | C++那些事