Перейти к содержимому
Теория · Шаблоны · урок 2 из 11

Вывод аргументов шаблона

Обычная функция double max_of(double a, double b) принимает вызов max_of(1, 2.5): аргумент 1 преобразуется в double. Шаблон с тем же телом этот вызов отвергает:

C++
#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';  // ✗
}
TEXT
error: no matching function for call to 'max_of'

Вывод из аргументов

В вызове шаблона тип T обычно не пишут: компилятор находит его сам. Это вывод аргументов шаблона (template argument deduction): компилятор сравнивает тип каждого аргумента с типом его параметра. Литерал 3 имеет тип int, поэтому для max_of(3, 7) получается T = int:

C++
std::cout << max_of(3, 7) << ' ' << max_of(2.5, 1.5) << '\n';  // 7 2.5

Сначала компилятор выводит T, а потом инстанцирует функцию для этого типа. Выведенный тип подставляется везде, где в шаблоне стоит T, в том числе в тип результата: max_of(2.5, 1.5) возвращает double.

Каждый аргумент выводит T независимо от остальных, и результаты должны совпасть. В max_of(1, 2.5) первый аргумент даёт int, а второй — double. Преобразования вроде int → double при выводе не применяются, поэтому выбрать один тип компилятор не может. Об этом говорит пояснение под ошибкой: deduced conflicting types for parameter 'T' ('int' vs. 'double').

Явный аргумент шаблона

Тип можно указать самому — в угловых скобках после имени шаблона. Такой явный аргумент шаблона (explicit template argument) заменяет вывод: T уже известен, и аргументы преобразуются, как при вызове обычной функции. Другой способ — передать аргументы одного типа: литерал 1.0 имеет тип double.

C++
std::cout << max_of<double>(1, 2.5) << ' ' << max_of(1.0, 2.5) << '\n';  // 2.5 2.5

Явный аргумент нужен и тогда, когда тип аргумента не выбрать самому. Вызов max_of(s.size(), 10) для строки s не скомпилируется: size() возвращает std::size_t, а 10 имеет тип int. Вызов max_of<std::size_t>(s.size(), 10) компилируется и возвращает большее из двух чисел.

Частая ошибка

Параметр T встречается только в типе результата, и тип ждут от переменной, которая получает результат:

C++
template <typename T>
T zero() {
    return T{};
}

int main() {
    double d = zero();  // ✗
}
TEXT
error: no matching function for call to 'zero'

Запись T{} создаёт значение типа T по умолчанию, как int x{}: для чисел это 0. Но у zero() нет аргументов, а тип переменной d в выводе не участвует. Поэтому компилятор поясняет: couldn't infer template argument 'T'. Укажите тип явно: zero<double>().