Function template

< cpp‎ | language
Revision as of 07:16, 15 May 2013 by Cubbi (Talk | contribs)

C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Function declaration
Lambda function declaration
inline specifier
Exception specifications (deprecated)
noexcept specifier (C++11)
decltype (C++11)
auto (C++11)
alignas (C++11)
Storage duration specifiers
Alternative representations
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Attributes (C++11)
typedef declaration
Type alias declaration (C++11)
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Class-specific function properties
Special member functions
Class template
Function template

A function template defines a family of functions.



template < Template:sparam > Template:sparam


Template:sparam 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.

Template:sparam 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.

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).

Explicit instantiation

template Template:sparam < Template:sparam > Template:sparam ( Template:sparam ) ; (1)
template Template:sparam Template:sparam ( Template:sparam ) > ; (2)
extern template Template:sparam < Template:sparam > Template:sparam ( Template:sparam) ; (3) (since C++11)
extern template Template:sparam Template:sparam ( Template:sparam) ; (4) (since C++11)
1) Explicit instantiation definition without template argument deduction
2) Explicit instantiatino 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)

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)

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, the pack is not deducible and must be specified, along with all the types that follow.
  • 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
  • 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 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 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))

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:

Function template specialization

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


See Also