Function template
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) | |||||||
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.
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 typeQ
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 ofA
is used in place ofA
for deduction. - If
A
is a function type, the pointer to this function type is used in place ofA
for deduction. - Otherwise, if
A
is a cv-qualified type, then the top level cv-qualifiers are ignored for deduction
- If
- 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 byP
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 toA
is used in place ofA
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
andA
identical, except thatThis section is incomplete
Reason: the three exceptions and the implicit conversions - 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))
}
This section is incomplete Reason: The huge amount of stuff from 14.8.2.5. Except it will have to be made easy-to-follow somehow |
[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:
This section is incomplete |
[edit] Function template specialization
This section is incomplete Reason: note that there is a page for specializations in general, only function specifics go here: lack of partials, interaction with function overloads |
[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
This section is incomplete Reason: actual rules from the std |
[edit] Example
This section is incomplete Reason: no example |