Variable Templates

An introduction to variable templates, allowing us to create variables at compile time.

Ryan McCombe
Updated

Let's introduce our second type of template - variable templates. Let's imagine we were creating a library for our colleagues to use. Our library needs mathematical constants, such as Pi:

constexpr double Pi {
  3.141592653589793238462643383279
}

We elected to use a double here, but that might be presumptuous. We don't know how our library is going to be used by our consumers, so the preferred type was just a guess. In some scenarios, they might prefer a float, or a custom type.

That conversion could be done at run time, but it would have a performance cost, and may reduce type safety.

We could create different versions of our variable:

constexpr int PiInt {
  3
};

constexpr double PiFloat {
  3.141592f
};

constexpr double PiDouble {
  3.141592653589793
};

But, this has the same disadvantages we saw when trying to create classes to accommodate different data types. Aside from the code duplication and the verbose names, this approach requires us to know all the types our users will want in advance.

Creating Variable Templates

Instead, we could create a variable template, using a template parameter in place of the type. In this example, our parameter will be a typename and we'll call it T:

template <typename T>
constexpr T Pi {
  3.141592653589793238462643383279
};

Now, we can ask our variable template to create new variables, using the < and > syntax. Given that this template requires a type as its parameter, would provide that type as an argument:

template <typename T>
constexpr T Pi{3.141592653589793238462643383279};

int main() {
  // Will be an integer initialized to 3
  auto IntegerPi{Pi<int>};
}

Variable Templates with Custom Types

Any time the compiler encounters the Pi template being invoked with a type that it hasn't seen, it will use the template to create a new variable, passing the literal 3.141... to that type's constructor.

Given this happens at compile time, the type must have a constructor that can accept that argument at compile time. In the following example, we instantiate Pi<CustomType>, where CustomType has a constexpr constructor that can accept the double:

#include <iostream>

template <typename T>
constexpr T Pi{3.141592653589793238462643383279};

struct CustomType {
  constexpr CustomType(double InitialValue)
    : Value{int(InitialValue)} {}

  int Value;
};

int main() {
  auto Container{Pi<CustomType>};

  std::cout << "Container Value: "
    << Container.Value;
}
Container Value: 3.14159

Non-Typename Parameters

Variable templates are not restricted to just setting the type of the generated variable. Our templates can have multiple parameters, and use them as needed to create a variable.

Below, we define a template that creates integers whose value is initialized to the result of calling the + operator on two integer parameters:

template <int x, int y>
constexpr int Result{x + y};

int main() {
  int MySum{Result<1, 2>};
}

Given this calculation is done at compile time, we can ensure there is no runtime performance impact which is ideal if our calculation is expensive, or performed frequently.

However, it also means the expressions we use in our template variable must be evaluable at compile time. In the previous example, operator+(int, int) meets this criterion, so our template is valid.

Summary

In this lesson, we learned about variable templates in C++. Here are the key takeaways:

  • Variable templates allow us to create variables with parameterized types, similar to class templates.
  • They provide flexibility and reusability by allowing the user to specify the desired type when instantiating the variable.
  • Variable templates can have multiple parameters and perform compile-time calculations.
  • It's recommended to mark variable templates as constexpr to prevent unexpected behavior due to shared instances.
  • Variable templates offer an alternative to creating multiple versions of variables for different types.
  • They enable us to create variables with custom types that have constexpr constructors.
  • Variable templates can be used for compile-time calculations, ensuring no runtime performance impact.
Next Lesson
Lesson 25 of 128

Function Templates

Understand the fundamentals of C++ function templates and harness generics for more modular, adaptable code.

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Variable Templates vs Variables
How do I choose between using a variable template and a regular variable?
Variable Templates with Custom Types
Can I use variable templates with user-defined types?
Variable Template Restrictions
Are there any limitations or restrictions when using variable templates?
Variable Templates vs Constexpr Variables
How do variable templates differ from constexpr variables?
Compile Time Constants using Templates
Can I use variable templates to create compile-time constants?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant