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

Шаблоны функций

Перегрузки twice(int) и twice(double) различаются только типом, а тело у них одно: return x * 2;. Для long и float понадобились бы ещё две такие же копии. Шаблон функции (function template) записывает тело один раз, а версии для нужных типов компилятор (compiler) создаёт сам:

C++
#include <iostream>

template <typename T>
T twice(T x) {
    return x * 2;
}

int main() {
    std::cout << twice(21) << ' ' << twice(1.25) << '\n';  // 42 2.5
}

Параметр шаблона

Шаблон функции — заготовка, по которой компилятор строит обычные функции. Строка template <typename T> объявляет параметр шаблона (template parameter) T — имя, которое обозначает тип. В параметрах, типе результата и теле T стоит там, где у обычной функции был бы int или double. Имя T — соглашение, подойдёт и Value, а вместо typename можно написать class.

Инстанцирование

Для вызова twice(21) компилятор подставляет int вместо T и получает функцию int twice(int x). Это инстанцирование (instantiation): по шаблону создаётся функция для конкретного типа. Вызов twice(1.25) создаёт вторую функцию — double twice(double x). Ещё один вызов с int использует уже созданную версию.

Тело шаблона компилятор проверяет для каждого типа отдельно. Для int и double выражение x * 2 допустимо. А строку std::string на 2 не умножить, поэтому вызов twice(std::string("ab")) не скомпилируется, хотя сам шаблон написан верно.

Шаблоны в заголовках

Чтобы создать версию для int, компилятору нужно тело шаблона, одного объявления (declaration) мало. Поэтому шаблон обычно пишут в заголовочном файле (header) twice.h целиком, вместе с телом:

C++
#pragma once

template <typename T>
T twice(T x) {
    return x * 2;
}

Если подключить такой заголовок в два .cpp-файла, определение (definition) обычной функции привело бы к ошибке multiple definition, а шаблону это не грозит. Правило одного определения (one definition rule) разрешает одинаковые определения шаблона в разных единицах трансляции (translation units), как и у inline-функций.

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

Шаблон разделили, как обычную функцию: в twice.h оставили объявление template <typename T> T twice(T x);, а тело перенесли в twice.cpp. Оба файла компилируются, но сборка (build) clang++ main.cpp twice.cpp не проходит:

C++
#include <iostream>
#include "twice.h"

int main() {
    std::cout << twice(21) << '\n';  // ✗
}
TEXT
undefined reference to `int twice<int>(int)'

Это сообщение компоновщика (linker), в задачах курса — undefined symbol. В twice.cpp нет вызова с int, поэтому версия для int там не создаётся. В main.cpp нет тела шаблона, и создать её здесь тоже нельзя. Перенесите тело в twice.h.