Лучшей иллюстрацией раздувания кода с шаблонами является использование шаблона для генерации кода, а не переменных. Типичная паника из-за того, что компилятор генерирует код для каждого экземпляра шаблона (трафарета). Это похоже на раздувание кода из-за встроенных функций и методов. Однако современные компиляторы и компоновщики могут выполнять магию для уменьшения размера кода в зависимости от настроек оптимизации.
Например:
template <typename Any_Type>
void Print_Hello(const Any_Type& v)
{
std::cout << "Hello, your value is:\n"
<< v
<< "\n";
return;
}
Приведенный выше код лучше всего рассматривать как трафарет. Компилятор сгенерирует код в зависимости от типа, переданного в Print_Hello
. Суть в том, что очень мало кода на самом деле зависит от переменной. (Который может быть уменьшен путем выделения кода и данных const.)
Опасение заключается в том, что компилятор будет генерировать код для каждого экземпляра, используя один и тот же тип переменной, создавая, таким образом, повторяющийся код:
int main(void)
{
int a = 5;
int b = 6;
Print_Hello(a); // Instantiation #1
Print_Hello(b); // Instantiation #2
return 0;
}
Страх также может быть расширен, когда шаблон (трафарет) создается в разных единицах перевода.
Современные компиляторы и линкеры умны. Умный компилятор распознает вызов функции шаблона и преобразует в какое-то уникальное искаженное имя. Компилятор будет использовать только один экземпляр для каждого вызова. Аналогично перегрузке функций.
Даже если компилятор был неаккуратным и генерировал несколько экземпляров функции (для одного и того же типа), компоновщик распознал бы дубликаты и поместил только один экземпляр в исполняемый файл.
При безукоризненном использовании шаблон функции или метода может добавить дополнительный код. Примерами являются большие функции, которые различаются по типу только в нескольких областях. Они имеют высокое отношение нетипизированного кода к типозависимому коду.
Реализация приведенного выше примера с меньшим количеством раздувания:
void Print_Prompt(void)
{
std::cout << "Hello, your value is:\n";
return;
}
template <typename Any_Type>
void Better_Print_Hello(const Any_Type& v)
{
Print_Prompt();
std::cout << v << "\n";
return;
}
Основное отличие состоит в том, что код, который не зависит от типа переменной, был преобразован в новую функцию. Это может показаться нецелесообразным для этого небольшого примера, но оно иллюстрирует концепцию. И концепция заключается в том, чтобы реорганизовать функцию в части, которые зависят от типа переменной, и те, которые не являются. Части, которые являются зависимыми, преобразуются в шаблонные функции.