Skip to content

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:

template <typename T>
using is_float = std::integral_constant<bool, std::is_same<T, float>::value>;

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:

template <typename T>
constexpr bool is_float = std::is_same<T, float>::value;

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

  1. Less redundant code: variable templates allow us to define variables based on types directly, avoiding the redundant code of encapsulating boolean values in a struct or std::integral_constant.
  2. Better readability: by simplifying the syntax, variable templates make the code clearer, especially when writing a large number of type traits.
  3. 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:

template <typename T>
constexpr bool is_float = std::is_same_v<T, float>;

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 类型需要更多内存

Comments