Function template

From cppreference.com
 
 
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 < argument-list > name ( parameter-list ) ; (1)
template return-type name ( parameter-list ) > ; (2)
extern template return-type < argument-list > name ( 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 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)

[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)
}

[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 deduced to operator<<<char, std::char_traits<char>> both times
    // std::endl is deduced to std::endl<char, std::char_traits<char>>
}

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

[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

[edit] Example

[edit] See Also