Как выглядит шаблонная функция после компиляции при ее вызове с аргументами разного типа?

«Как выглядит шаблонная функция после компиляции при ее вызове с аргументами разного типа?» — вопрос из категории Шаблоны, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Компилятор C++ выполняет инстанцирование шаблона, генерируя отдельную, конкретную версию функции (или класса) для каждого уникального набора шаблонных параметров, с которым она используется. Эти сгенерированные функции являются обычным машинным кодом.

Процесс:

  1. Компилятор видит вызов шаблонной функции с конкретными типами.
  2. Он подставляет эти типы вместо параметра шаблона T.
  3. Генерирует новую функцию с «зашитым» типом и компилирует ее.

Пример:

// Шаблонная функция (исходный код)
template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    auto r1 = add(5, 10);      // Вызов с int
    auto r2 = add(3.14, 2.71); // Вызов с double
    auto r3 = add('A', 1);     // Ошибка компиляции: типы 'char' и 'int' разные
    // Явное указание типа решает проблему:
    auto r4 = add<int>('A', 1); // char неявно приводится к int
}

После компиляции условно будут сгенерированы две независимые функции (манглинг имен упрощен):

// Сгенерированный код (пример)
int add_int(int a, int b) { // Инстанцирование для T = int
    return a + b;
}

double add_double(double a, double b) { // Инстанцирование для T = double
    return a + b;
}

Важные следствия:

  • Раздувание бинарного кода (code bloat): Каждая инстанцированная версия увеличивает размер исполняемого файла.
  • Компиляция только используемых инстанциаций: Если add ни разу не вызвана для std::string, эта версия сгенерирована не будет.
  • Определение в заголовочном файле: Поскольку инстанцирование происходит на этапе компиляции, тело шаблонной функции должно быть видно в каждой единице трансляции, где она используется. Поэтому шаблоны почти всегда определяются полностью в .hpp файлах.