Last updated:2026-10-12
C++17 Variable Templates¶
Variable Templates from C++那些事¶
When writing template code, we often need to define and use various type traits. These traits are usually used to reason about types at compile time; the std::is_const, std::is_same, and std::is_reference provided by the STL are examples of exactly that. With these traits, developers can make compile-time decisions based on type properties.
This article introduces how to use C++14 variable templates to simplify writing type traits, together with a simple example.
C++11¶
In C++11, writing a type trait usually involves using a struct or std::integral_constant to encapsulate a boolean value. For example, to write a trait is_float that checks whether a type is float, we can implement it as follows:
template <typename T>
struct is_float {
static constexpr bool value = std::is_same<T, float>::value;
};
Or, slightly more concisely, using a type alias and std::integral_constant:
Although this is more concise than using a struct directly, in the end we are still defining a type rather than getting a boolean value directly. To use this trait, the boolean value has to be obtained through the ::value member:
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;
}
}
This works, but there are still two shortcomings:
1. Every use of the trait requires accessing ::value.
2. Defining a new trait requires declaring a new type or type alias, which adds code redundancy.
The introduction of C++14 variable templates¶
C++14 introduced variable templates, allowing us to define variables that depend on types directly. This feature simplifies writing type traits: instead of wrapping boolean values in type aliases or structs, we can define the boolean value directly.
The rewritten is_float trait looks like this:
This form is clearer and more concise, removing unnecessary code. It is also more convenient to use:
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;
}
}
Compared with the previous way of writing it, with variable templates there is no longer any need to access the boolean value through ::value, and the code is more concise and intuitive.
Advantages of variable templates¶
- Less redundant code: variable templates allow us to define variables based on types directly, avoiding the redundant code of encapsulating boolean values in a
structorstd::integral_constant. - Better readability: by simplifying the syntax, variable templates make the code clearer, especially when writing a large number of type traits.
- Template specialization support: unlike type alias templates, variable templates can be specialized, both fully and partially. We can define dedicated logic for specific types without worrying about extensibility.
Further improvements in C++17¶
C++17 further extended the application of variable templates by providing a variable template helper for every type trait. For example, std::is_same gained the std::is_same_v variable template, which simplifies accessing the value of a type trait:
In this way, using type traits becomes more concise: developers can take advantage of variable templates directly without accessing ::value every time.
A real-world case¶
This feature is used quite a lot in practice. For example, when allocating memory blocks of different sizes in a database, we can initialize the block size for different types via templates.
template <typename T>
constexpr size_t block_size = 1024; // 默认大小
template <>
constexpr size_t block_size<double> = 2048; // double 类型需要更多内存
Related Topics¶
- C++17 [[nodiscard]] Attribute | C++那些事
- C++17 std::string_view | C++那些事
- C++17 PMR Memory Resources | C++那些事
- C++17 Seventeen Advanced Features | C++那些事
- C++17 Class Template Argument Deduction CTAD | C++那些事
- C++17 optional_ref | C++那些事
- C++17 std::variant | C++那些事
- C++17 Structured Bindings | C++那些事
- C++17 Template auto Deduction | C++那些事