Function template

From cppreference.com
< cpp‎ | language
 
 
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements
Jump statements
Functions
function declaration
lambda function declaration
function template
inline specifier
exception specifications (deprecated)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
decltype specifier (C++11)
Specifiers
cv specifiers
storage duration specifiers
constexpr specifier (C++11)
auto specifier (C++11)
alignas specifier (C++11)
Initialization
Literals
Expressions
alternative representations
Utilities
Types
typedef declaration
type alias declaration (C++11)
attributes (C++11)
Casts
implicit conversions
const_cast conversion
static_cast conversion
dynamic_cast conversion
reinterpret_cast conversion
C-style and functional cast
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
class template
function template
template specialization
parameter packs (C++11)
Miscellaneous
Inline assembly
 

A function template defines a family of functions.

Contents

[edit] Syntax

template < parameter-list > declaration

[edit] Explanation

declaration defines or declares a class (including struct and union), a member class or member enumeration type, a function or member function, a static data member of a class template, or a type alias. It may also define a template specialization. This page focuses on function templates.

parameter-list is a non-empty comma-separated list of the template parameters, each of which is either non-type parameter, a type parameter, a template parameter, or a parameter pack of any of those. For function templates, template parameters are declared in the same manner as for class templates: see class template page for details.

[edit] Function template instantiation

A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or class, from a class template).

[edit] Explicit instantiation

template return-type name < argument-list > ( parameter-list ) ; (1)
template return-type name ( parameter-list ) ; (2)
extern template return-type name < argument-list > ( parameter-list ) ; (3) (since C++11)
extern template return-type name ( parameter-list ) ; (4) (since C++11)
1) Explicit instantiation definition without template argument deduction
2) Explicit instantiation definition with template argument deduction
3) Explicit instantiation declaration without template argument deduction
4) Explicit instantiation declaration with template argument deduction

An explicit instantiation definition forces instantiation of the function or member function they refer to. It may appear in the program anywhere after the template definition, and for a given argument-list, is only allowed to appear once in the program.

An explicit instantiation declaration (an extern template) prevents implicit instantiations: the code that would otherwise cause an implicit instantiation has to use the explicit instantiation definition provided somewhere else in the program.

template<typename T>
void f(T s)
{
    std::cout << s << '\n';
}
 
template void f<double>(double); // instantiates f<double>(double)
template void f<>(char); // instantiates f<char>(char)
template void f(int); // instantiates f<int>(int)

[edit] Implicit instantiation

When code refers to a function in context that requires the function definition to exist, and this particular function has not been explicitly instantiated, implicit instantiation occurs. The list of template arguments does not have to be supplied if it can be deduced from context

#include <iostream>
 
template<typename T>
void f(T s)
{
    std::cout << s << '\n';
}
 
int main()
{
    f<double>(1); // instantiates and calls f<double>(double)
    f<>('a'); // instantiates and calls f<char>(char)
    f(7); // instantiates and calls f<int>(int)
    void (*ptr)(std::string) = f; // instantiates f<string>(string)
}


Note: omitting <> entirely allows overload resolution to examine both template and non-template overloads.

[edit] Template argument deduction

In order to instantiate a function template, every template argument must be known, but not every template argument has to be specified. When possible, the compiler will deduce the missing template arguments from the function arguments. This occurs when a function call is attempted and when an address of a function template is taken.

template<typename To, typename From> To convert(From f);
 
void g(double d) 
{
    int i = convert<int>(d); // calls convert<int,double>(double)
    char c = convert<char>(d); // calls convert<char,double>(double)
    int(*ptr)(float) = convert; // instantiates convert<int, float>(float)
}

This mechanism makes it possible to use template operators, since there is no syntax to specify template arguments for an operator other than by re-writing it as a function call expression.

#include <iostream>
int main() 
{
    std::cout << "Hello, world" << std::endl;
    // operator<< is looked up via ADL as std::operator<<,
    // then deduced to operator<<<char, std::char_traits<char>> both times
    // std::endl is deduced to std::endl<char, std::char_traits<char>>
}

Template argument deduction takes place after the function template name lookup (which may involve argument-dependent lookup) and before overload resolution.

For each function parameter of type P specified in the function template, the compiler examines the corresponding function call argument of type A as follows:

  • If P is a (possibly cv-qualified, possibly reference to) std::initializer_list<Q> and the function call argument is a brace-enclosed list of initializers, argument deduction is attempted between the type Q and each element of the braced-init-list, which all must match
template<class Q>
void f(std::initializer_list<Q>);
 
int main()
{
    f({1,2,3});    // OK: calls void f(initializer_list<int>)
//  f({1,"asdf"}); // error: Q can't be both int and const char*
}
  • Otherwise, if the function call argument is a braced-init-list, the type cannot be deduced and must be specified
template<class T>
void f(T);
 
int main()
{
//  f({1,2,3}); // error: T cannot be deduced from a braced-init-list
    f<std::vector<int>>({1,2,3}); // OK, T is specified
}
  • If the function template ends with a parameter pack, each remaining argument is compared with the type of the parameter pack and each comparison deduces the next type in the expansion.
template<class H, class ...Tail>
void f(H, Tail...);
 
int main()
{
    int x; double y; char z;
    f(x, y, z); // H = int, Tail = {double, char}
}
  • If a function template has a parameter pack that is not at the end of its parameter declaration list, the pack is not deducible and must be specified, along with all the types that follow (unless there are default parameters).
template<class... pack1, class T>
void f1(T n, pack1... args) {}
 
template<class... pack1, class T>
void f2(pack1... args, T n) {}
 
template<int...> struct T {};
 
template<int... pack1, int N, int... pack2>
void g1(const T<N, pack1...>& arg1, const T<N, pack2...>&) {}
 
template<int... pack1, int N, int... pack2>
void g2(const T<pack1..., N>& arg1, const T<N, pack2...>&) {}
 
int main()
{
    f1(1,2,3,4); // okay, N=1, pack1={2,3,4}
//  f2(1,2,3,4); // error: parameter pack in f2's parameter list is not last
 
    T<1,2> t1;
    T<1,-1,0> t2;
    g1(t1, t2); // okay, N=1, pack1 = {2}, pack2={-1,0}
//  g2(t1, t2); // error: parameter pack in g2's first argument's template
                // parameter list is not last
}


  • If P is a non-reference type,
  • If A is an array type, the pointer to an element of A is used in place of A for deduction.
  • If A is a function type, the pointer to this function type is used in place of A for deduction.
  • Otherwise, if A is a cv-qualified type, then the top level cv-qualifiers are ignored for deduction
#include <utility>
#include <iostream>
 
template <class T>
void array_to_pointer(T)
{
    static_assert(std::is_same<T, int*>::value, "");
}
 
template <class T>
void func_to_pointer(T)
{
    static_assert(std::is_same<T, void(*)(int)>::value, "");
}
 
template <class T>
void cv_ignored(T)
{
    static_assert(std::is_same<T, int>::value, "");
}
 
void foo(int) {}
 
int main()
{
    int a[3];
    static_assert(std::is_same<decltype(a), int[3]>::value, "");
    array_to_pointer(a); // array to pointer conversion: T = 'int*'
 
    static_assert(std::is_same<decltype(foo), void(int)>::value, "");
    func_to_pointer(foo); // function to pointer conversion: T = 'void(*)(int)'
 
    const int b = 13;
    static_assert(std::is_same<decltype(b), const int>::value, "");
    cv_ignored(b); // cv-qualifier ignored: T = 'int'
 
    std::cout << "done\n";
}


  • If P is a cv-qualified type, the top-level cv qualifiers are ignored for deduction.
  • If P is a reference type, the type referred to by P is used for deduction.
  • If P is an rvalue reference to a cv-unqualified template parameter, and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction (Note: this is the basis for the action of std::forward)
template <class T>
int f(T&&); // P is rvalue reference to cv-unqualified T (special case)
 
template <class T>
int g(const T&&); // P is rvalue reference to cv-qualified T (not special)
 
int main()
{
    int i;
    int n1 = f(i); // argument is lvalue:     calls f<int&>(int&) (special case)
    int n2 = f(0); // argument is not lvalue: calls f<int>(int&&)
 
//    int n3 = g(i); // error: deduces to g<int>(const int&&), which
//    // cant bind an rvalue reference to an lvalue:
}
  • After these transformations, the deduction process attempts to find such template arguments that would make P and A identical, except that:
  • If the original P is a reference type, the deduced A (i.e., the type referred to by the reference) can be more cv-qualified than the transformed A.
  • The transformed A can be another pointer or pointer to member type that can be converted to the deduced A via a qualification conversions.
  • If P is a class and P has the form simple-template-id, then the transformed A can be a derived class of the deduced A. Likewise, if P is a pointer to a class of the form simple-template-id, the transformed A can be a pointer to a derived class pointed to by the deduced A.
#include <iostream>
#include <utility>
 
template<class T>
void func_1(const T& t)
{
    static_assert(std::is_same<T, bool>::value, "");
    static_assert(std::is_same<decltype(t), const bool&>::value, "");
}
 
template<class T>
void func_2(volatile T* t)
{
    static_assert(std::is_same<T, int>::value, "");
    static_assert(std::is_same<decltype(t), volatile int*>::value, "");
}
 
template<class T>
class Foo {};
 
class Boo : public Foo<int> {};
 
template<template <class> class T1, class T2>
void func_3(T1<T2>* t)
{
    static_assert(std::is_same<T1<T2>, Foo<int>>::value, "");
    static_assert(std::is_same<T2, int>::value, "");
    static_assert(std::is_same<decltype(t), Foo<int>*>::value, "");
}
 
int main()
{
    bool a = false;
    static_assert(std::is_same<decltype(a), bool>::value, "");
    // transformed A = 'bool'
    // deducted A can be more cv-qualified = 'const bool'
    func_1(a);
 
    int* b = nullptr;
    static_assert(std::is_same<decltype(b), int*>::value, "");
    // transformed A = 'int*'
    // converted via qualification conversion to deducted A = 'volatile int*'
    func_2(b);
 
    Boo c;
    static_assert(std::is_same<decltype(&c), Boo*>::value, "");
    // transformed A = 'Boo*'
    // can be a derived class, deducted A = 'Foo<int>*'
    func_3(&c);
 
    std::cout << "done\n";
}


  • If P is a function type, pointer to function, or pointer to member function,
  • If the argument is a set of overloaded functions that includes at least one function template, the parameter cannot be deduced.
  • If the argument is a set of overloaded functions not containing function templates, template argument deduction is attempted with each overload. If only one succeeds, that successful deduction is used. If more than one succeeds, the template parameter cannot be deduced.
template <class T>
int f(T (*p)(T));
 
int g(int);
int g(char); // two overloads
 
int main()
{
    int i = f(g); // only one overload works: calls f(int (*)(int))
}
Alias templates are never deduced
template<class T> struct Alloc {};
template<class T> using Vec = vector<T, Alloc<T>>;
Vec<int> v;
 
template<template<class,class> class TT> void g(TT<int, Alloc<int>>);
g(v); // ok: deduces TT = vector
 
template<template<class> class TT> void f(TT<int>);
f(v); // error: TT cannot be deduced as "Vec" because Vec is an alias template

[edit] Template argument substitution

When a template argument is specified explicitly, but does not match the type of the corresponding function argument exactly, the template argument is adjusted by the following rules:

[edit] Function template specialization

[edit] Overload resolution

To compile a call to a function template, the compiler has to decide between non-template overloads, template overloads, and the specializations of the template overloads.

template< class T > void f(T);              // template overload
template< class T > void f(T*);             // template overload
void                     f(double);         // nontemplate overload
template<>          void f(int);            // specialization of #1
 
f('a');        // calls #1
f(new int(1)); // calls #2
f(1.0);        // calls #3
f(1);          // calls #4

Note that only non-template and primary template overloads participate in overload resolution. The specializations are not overloads and are not considered. Only after the overload resolution selects the best-matching primary function template, its specializations are examined to see if one is a better match.

template< class T > void f(T);    // overload #1 for all types
template<>          void f(int*); // specialization of #1 for pointers to int
template< class T > void f(T*);   // overload #2 for all pointer types
 
f(new int(1)); // calls #2, even though #1 would be a perfect match

For detailed rules on overload resolution, see overload resolution

[edit] See Also