Перейти к содержимому
Теория · Шаблоны · урок 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 обычно не пишут: компилятор находит его сам. Это вывод аргументов шаблона: компилятор сравнивает тип каждого аргумента с типом его параметра. Литерал 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').

Пройдите по шагам вызов max_of(1, 2.5) и посмотрите, как каждый аргумент даёт свой T, а потом сравните с max_of<double>(1, 2.5).

ВживуюКак компилятор выводит Tшаг 3 из 3 · итог
template <typename T>
T max_of(T a, T b)
T a
1int
T = int
T b
2.5double
T = double
error: no matching function for call to 'max_of' note: candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'double')
Созданные функции:пока ни одной

Выводы не совпали: int против double. Шаблон отброшен, другой подходящей функции нет — ошибка компиляции.

Выберите вызов и пройдите его по шагам

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

Тип можно указать самому — в угловых скобках после имени шаблона. Такой явный аргумент шаблона заменяет вывод: 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>().

Главное

  • Компилятор выводит T из типов аргументов, каждый аргумент — отдельно.
  • При выводе преобразования не применяются: max_of(1, 2.5) не скомпилируется.
  • Явный аргумент шаблона max_of<double>(1, 2.5) заменяет вывод, и аргументы преобразуются.
  • Тип переменной, которая получает результат, в выводе не участвует.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом