Template argument deduction
An ordinary function double max_of(double a, double b) accepts the call max_of(1, 2.5): the argument 1 converts to double. A template with the same body rejects this call:
#include <iostream>
template <typename T>
T max_of(T a, T b) {
return a > b ? a : b;
}
int main() {
std::cout << max_of(1, 2.5) << '\n'; // ✗
}error: no matching function for call to 'max_of'Deduction from arguments
A call to a template usually does not name the type T: the compiler finds it itself. This is template argument deduction: the compiler compares the type of each argument with the type of its parameter. The literal 3 has the type int, so max_of(3, 7) gets T = int:
std::cout << max_of(3, 7) << ' ' << max_of(2.5, 1.5) << '\n'; // 7 2.5The compiler first deduces T and then instantiates the function for that type. The deduced type replaces T everywhere in the template, the return type included: max_of(2.5, 1.5) returns a double.
Each argument deduces T independently of the others, and the results must match. In max_of(1, 2.5), the first argument gives int and the second gives double. Conversions such as int → double are not applied during deduction, so the compiler cannot pick one type. The note under the error says so: deduced conflicting types for parameter 'T' ('int' vs. 'double').
Explicit template argument
The type can be given by hand, in angle brackets after the template's name. Such an explicit template argument replaces deduction. T is already known, and the arguments convert as in a call to an ordinary function. Another way is to pass arguments of one type: the literal 1.0 has the type double.
std::cout << max_of<double>(1, 2.5) << ' ' << max_of(1.0, 2.5) << '\n'; // 2.5 2.5An explicit argument is also needed when you cannot choose an argument's type yourself. For a string s, the call max_of(s.size(), 10) does not compile: size() returns std::size_t, and 10 has the type int. The call max_of<std::size_t>(s.size(), 10) compiles and returns the larger of the two numbers.
Common mistake
The parameter T appears only in the return type, and the variable that receives the result is expected to supply the type:
template <typename T>
T zero() {
return T{};
}
int main() {
double d = zero(); // ✗
}error: no matching function for call to 'zero'T{} creates a default value of type T, as int x{} does: for numbers it is 0. But zero() has no arguments, and the type of the variable d takes no part in deduction. That is why the compiler adds: couldn't infer template argument 'T'. Give the type explicitly: zero<double>().