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 (see example). In other words, a function template represents a family of functions. The format for declaring function templates with type parameters is: template Declaration; template Declaration; 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. (It can be a basic type such as int or double.) For example, the C++ Standard Library contains the function template max(x, y) which returns the larger of x and y. That function template could be defined like this: template
nodiscard constexpr T& max(const T& a, const T& b) noexcept { return a This single function definition works with many data types. Specifically, it works with all data types for which '''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() { // This will call max by implicit argument deduction. std::println("{}", std::max(3, 7)); // This will call max by implicit argument deduction. std::println("{}", std::max(3.0, 7.0)); // We need to explicitly specify the type of the arguments; // although std::type_identity could solve this problem... std::println("{}", max(3, 7.0)); } 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(3, 7.0) 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, using auto 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(T x); void f1(auto x); // equivalent to (if Concept1 is a concept): // // void f2(T x); void f2(Concept1 auto x); // equivalent to (if Concept2 is a concept): // template // void f3(Ts... xs) void f3(Concept2 auto... xs); // equivalent to (if Concept2 is a concept): // template // void f4(T... xs); void f4(Concept2 auto xs, ...); // equivalent to (if Concept3 and Concept4 are concepts): // template // f5(const T* t, U& u); void f5(const Concept3 auto* t, Concept4 auto& u); Constraining the max() using concepts could look something like this: using std::totally_ordered; // in typename declaration: template
nodiscard constexpr T max(T x, T y) noexcept { return x requires totally_ordered
nodiscard constexpr T max(T x, T y) noexcept { return x
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 as
vector.
Variable templates In C++14, templates can be also used for variables, as in the following example: template constexpr T PI = T{3.141592653589793238462643383L}; // (Almost) 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 with template 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 (representing the type of object that the array holds) and a number which is of type
std::size_t (representing the number of elements the array holds). 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 myArray;
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 (or class) 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 (function templates cannot be partially specialized). • If all of the parameters are specialized it is a
full specialization. Explicit specialization is used when the behavior of a function or class for particular choices of the template parameters must deviate from the generic behavior: that is, from the code generated by the main template, or templates. For example, the template definition below defines a specific implementation of max() for arguments of type const char*: import std; template <>
nodiscard constexpr const char* max(const char* a, const char* b) noexcept { // Normally, the result of a direct comparison // between two C strings is undefined behaviour; // using std::strcmp makes defined. return std::strcmp(a, b) > 0 ? a : b; }
Variadic templates C++11 introduced
variadic templates, which can take a variable number of arguments in a manner somewhat similar to
variadic functions such as std::printf. using std::format_string; using std::ofstream; enum class Level { ... }; ofstream logFile{"logfile.txt"}; template void log(const format_string& fmt, Args&&... args) { std::println(logFile, fmt, args...); } 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 Alloc = std::allocator> > using TreeMap = std::map; template , 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 = HashMap template using StringHashMap = HashMap; StringHashMap myMap = /* something here... */;
Constrained templates Since
C++20, templates can be constrained similarly to
generics wildcards in
Java or
C# and
Rust where clauses. This is done using
concepts, which represent a set of boolean predicates evaluated at compile time. For example, this code defines a concept representing an upper bound on inheritance. A class satisfies this concept if it inherits from Player, and classes that do not cannot be used as the template parameter in processListOfPlayers(). import std; using std::is_base_of_v; using std::vector; class Player { // ... }; template concept ExtendsPlayer = is_base_of_v; // T is required to be a type whose inheritance upper bound is Player, // blocking any type that does not inherit from Player template void processListOfPlayers(vector players) { // ... }
Exported templates In
C++03, "exported templates" were added to C++. These were later removed in
C++11, due to very few compilers actually supporting the feature. The only compiler known to support exported templates was
Comeau C/C++. Among the cited reasons for removal were: • Expensive or complex to implement • Little benefit to most users as well as little interest • Difficult to use • Changes to meanings of existing language features • Restricting the future development of C++ An "exported template" is essentially a class template whose static data members and non-inline methods are exported. It must be marked by the keyword export. What distinguishes an "exported template" is the fact that it does not need to be defined in a
translation unit that uses the template. For example (in C++03): : • include static void trace() { std::cout T min(const T& x, const T& y); int main() { trace(); std::cout : • include static void trace() { std::cout T min(const T& x, const T& y) { trace(); return a With the introduction of
modules in
C++20, the keyword export was re-added to C++. This re-allowed declarations like this: import std; using std::is_base_of_v; export class Atom { // ... }; export template concept ExtendsAtom = is_base_of_v; export template class Cluster: public Bases... { private: Instance x; public: explicit Cluster(Instance x, Bases&&... bases): Bases(bases)..., x{x} {} // ... }; The compilation speed benefits intended to be offered by exported templates are offered by modules anyway, making the feature essentially obsolete and superseded by modules. == Generic programming features in other languages ==