Ответ
Компилятор C++ выполняет инстанцирование шаблона, генерируя отдельную, конкретную версию функции (или класса) для каждого уникального набора шаблонных параметров, с которым она используется. Эти сгенерированные функции являются обычным машинным кодом.
Процесс:
- Компилятор видит вызов шаблонной функции с конкретными типами.
- Он подставляет эти типы вместо параметра шаблона
T. - Генерирует новую функцию с «зашитым» типом и компилирует ее.
Пример:
// Шаблонная функция (исходный код)
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файлах.