C++ Templates

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Extensions
> Step 2: And Like the video. BONUS: You can also share it!

Introduction

Classes, functions, and (since C++14) variables can be templated. A template is a piece of code with some free parameters that will become a concrete class, function, or variable when all parameters are specified. Parameters can be types, values, or themselves templates. A well-known template is std::vector, which becomes a concrete container type when the element type is specified, e.g., std::vector<int>.

Syntax

  • template < template-parameter-list > declaration
  • export template < template-parameter-list > declaration /* until C++11 */
  • template <> declaration
  • template declaration
  • extern template declaration /* since C++11 */
  • template < template-parameter-list > class ...(opt) identifier(opt)
  • template < template-parameter-list > class identifier(opt) = id-expression
  • template < template-parameter-list > typename ...(opt) identifier(opt) /* since C++17 */
  • template < template-parameter-list > typename identifier(opt) = id-expression /* since C++17 */
  • postfix-expression . template id-expression
  • postfix-expression -> template id-expression
  • nested-name-specifier template simple-template-id ::

Remarks

The word template is a keyword with five different meanings in the C++ language, depending on the context.

  1. When followed by a list of template parameters enclosed in <>, it declares a template such as a class template, a function template, or a partial specialization of an existing template.

    template <class T>
    void increment(T& x) { ++x; }
    
  2. When followed by an empty <>, it declares a an explicit (full) specialization.

    template <class T>
    void print(T x);
    
    template <> // <-- keyword used in this sense here
    void print(const char* s) {
        // output the content of the string
        printf("%s\n", s);
    }
    
  3. When followed by a declaration without <>, it forms an explicit instantiation declaration or definition.

    template <class T>
    std::set<T> make_singleton(T x) { return std::set<T>(x); }
    
    template std::set<int> make_singleton(int x); // <-- keyword used in this sense here
    
  4. Within a template parameter list, it introduces a template template parameter.

    template <class T, template <class U> class Alloc>
    //                 ^^^^^^^^ keyword used in this sense here
    class List {
        struct Node {
            T value;
            Node* next;
        };
        Alloc<Node> allocator;
        Node* allocate_node() {
            return allocator.allocate(sizeof(T));
        }
        // ...
    };
    
  5. After the scope resolution operator :: and the class member access operators . and ->, it specifies that the following name is a template.

    struct Allocator {
        template <class T>
        T* allocate();
    };
    
    template <class T, class Alloc>
    class List {
        struct Node {
            T value;
            Node* next;
        }
        Alloc allocator;
        Node* allocate_node() {
            // return allocator.allocate<Node>();       // error: < and > are interpreted as
                                                        // comparison operators
            return allocator.template allocate<Node>(); // ok; allocate is a template
            //               ^^^^^^^^ keyword used in this sense here
        }
    };
    

Before C++11, a template could be declared with the export keyword, making it into an exported template. An exported template's definition does not need to be present in every translation unit in which the template is instantiated. For example, the following was supposed to work:

foo.h:

#ifndef FOO_H
#define FOO_H
export template <class T> T identity(T x);
#endif

foo.cpp:

#include "foo.h"
template <class T> T identity(T x) { return x; }

main.cpp:

#include "foo.h"
int main() {
    const int x = identity(42); // x is 42
}

Due to difficulty of implementation, the export keyword was not supported by most major compilers. It was removed in C++11; now, it is illegal to use the export keyword at all. Instead, it is usually necessary to define templates in headers (in contrast to non-template functions, which are usually not defined in headers). See Why can templates only be implemented in the header file?



Got any C++ Question?