Template (C++)
Templates are a feature of the C++ programming language that allow functions and classes to operate with generic types. This allows a function or class declaration to reference via a generic variable another different class without creating a full declaration for each of these different classes.
In plain terms, a templated class or function would be the equivalent of copying and pasting the templated block of code where it is used, and then replacing the template parameter with the actual one. For this reason, classes employing templated methods place the implementation in the headers as no symbol could be compiled without knowing the type beforehand.
The C++ Standard Library provides many useful functions within a framework of connected templates.
Major inspirations for C++ templates were the parameterized modules provided by the language CLU and the generics provided by Ada.
Technical overview
There are three kinds of templates: function templates, class templates and, since C++14, variable templates. Since C++11, templates may be either variadic or non-variadic; in earlier versions of C++ they are always non-variadic.C++ Templates are Turing complete.
Function templates
A function template behaves like a function except that the template can accept arguments of various types, enabling type-generic behavior. In other words, a function template represents a family of functions. The format for declaring function templates with type parameters is:template
template
Both expressions have the same meaning and behave in exactly the same way. The latter form was introduced to avoid confusion, since a type parameter need not be a class until C++20.
For example, the C++ Standard Library contains the function template
max which returns the larger of x and y. That function template could be defined like this:template
nodiscard
constexpr T& max noexcept
This single function definition works with many data types. Specifically, it works with all data types for which < is defined and returns a value with a type convertible to
bool. The usage of a function template saves space in the source code file in addition to limiting changes to one function description and making the code easier to read.An instantiated function template usually produces the same object code, though, compared to writing separate functions for all the different data types used in a specific program. For example, if a program uses both an
int and a double version of the max function template above, the compiler will create an object code version of max that operates on int arguments and another object code version that operates on double arguments. The compiler output will be identical to what would have been produced if the source code had contained two separate non-templated versions of max, one written to handle int and one written to handle double.Here is how the function template could be used:
import std;
int main
In the first two cases, the template argument
T is automatically deduced by the compiler to be int and double, respectively. In the third case automatic deduction of max would fail because the type of the parameters must in general match the template arguments exactly. Therefore, we explicitly instantiate the double version with max.This function template can be instantiated with any copy-constructible type for which the expression
y < x is valid. For user-defined types, this implies that the less-than operator must be overloaded in the type.Abbreviated function templates
Since C++20, usingauto or concept auto in any of the parameters of a function declaration, that declaration becomes an abbreviated function template declaration. Such a declaration declares a function template and one invented template parameter for each placeholder is appended to the template parameter list:// equivalent to:
// template
// void f1;
void f1;
// equivalent to :
//
// void f2;
void f2;
// equivalent to :
// template
// void f3
void f3;
// equivalent to :
// template
// void f4;
void f4;
// equivalent to :
// template
// f5;
void f5;
Constraining the
max using concepts could look something like this:using std::totally_ordered;
// in typename declaration:
template
nodiscard
constexpr T max noexcept
// in requires clause:
template
requires totally_ordered
nodiscard
constexpr T max noexcept
Class templates
A class template provides a specification for generating classes based on parameters. Class templates are generally used to implement containers. A class template is instantiated by passing a given set of types to it as template arguments. The C++ Standard Library contains many class templates, in particular the containers adapted from the Standard Template Library, such asvector.Variable templates
In C++14, templates can be also used for variables, as in the following example:template
constexpr T PI = T; // from std::numbers::pi
Non-type template parameters
Although templating on types, as in the examples above, is the most common form of templating in C++, it is also possible to template on values. Thus, for example, a class declared withtemplate
class MyClass;
can be instantiated with a specific
int.As a real-world example, the standard library fixed-size array type
std::array is templated on both a type and a number which is of type std::size_t. To create a class Array equivalent to std::array, it can be declared as follows:template
struct Array;
and an array of six
chars might be declared:Array
Template specialization
When a function or class is instantiated from a template, a specialization of that template is created by the compiler for the set of arguments used, and the specialization is referred to as being a generated specialization.Explicit template specialization
Sometimes, the programmer may decide to implement a special version of a function for a given set of template type arguments which is called an explicit specialization. In this way certain template types can have a specialized implementation that is optimized for the type or a more meaningful implementation than the generic implementation.- If a class template is specialized by a subset of its parameters it is called partial template specialization.
- If all of the parameters are specialized it is a full specialization.
max for arguments of type const char*:import std;
template <>
nodiscard
constexpr const char* max noexcept
Variadic templates
C++11 introduced variadic templates, which can take a variable number of arguments in a manner somewhat similar to variadic functions such asstd::printf.using std::format_string;
using std::ofstream;
enum class Level ;
ofstream logFile;
template
void log
Because only C-style variadic parameters are supported in C++, the only way to get type-safe variadic functions (like in Java is through variadic templates.
Template aliases
C++11 introduced template aliases, which act like parameterized typedefs.The following code shows renaming
std::map to TreeMap and std::unordered_map to HashMap, as well as creating an alias StringHashMap for std::unordered_map. This allows, for example, StringHashMap to be used as shorthand for std::unordered_map.using String = std::string;
// allowing optional specialization of hash functions, allocators, etc.
template <
typename K,
typename V,
typename Compare = std::less
typename Alloc = std::allocator
using TreeMap = std::map
template <
typename K,
typename V,
typename HashFn = std::hash
typename KeyEq = std::equal_to
typename Alloc = std::allocator
>
using HashMap = std::unordered_map
// or, only allowing K and V to be specialized:
template
using TreeMap = std::map
template
using HashMap = std::unordered_map
// Defining StringHashMap
template
using StringHashMap = HashMap
StringHashMap