Краткий ответ таков: принцип «вы платите только за то, что используете» по-прежнему действует точно так же, как и раньше.
Более длинный ответ можно увидеть, сравнив сгенерированный код для двух гипотетических реализаций, например.
#include <iostream>
template <typename T>
void func1(T& v) {
v = -10;
}
template <typename T1, typename T2>
void func1(T1& v1, T2& v2) {
func1(v1); func1(v2);
}
// More unused overloads....
template <typename T1, typename T2, typename T3>
void func1(T1& v1, T2& v2, T3& v3) {
func1(v1); func1(v2); func1(v3);
}
int main() {
double d;
int i;
func1(d);
func1(i);
std::cout << "i=" << i << ", d=" << d << std::endl;
func1(d,i);
std::cout << "i=" << i << ", d=" << d << std::endl;
}
С современным компилятором это в значительной степени сводится к тому, что вы написали бы, если бы хотели полностью избежать шаблонов. В этом «традиционном» шаблонном коде C++03 моя версия g++ встраивается (в компиляторе, а не в ключевом слове) целиком, и нет очевидного намека на то, что инициализация выполняется через ссылку в функции шаблона, несколько раз, в разных способы.
По сравнению с эквивалентным вариативным подходом:
#include <iostream>
#include <functional>
void func1() {
// end recursion
}
template <typename T, typename ...Args>
void func1(T& v, Args&... args) {
v = -10;
func1(args...);
}
int main() {
double d;
int i;
func1(d);
func1(i);
std::cout << "i=" << i << ", d=" << d << std::endl;
func1(d,i);
std::cout << "i=" << i << ", d=" << d << std::endl;
}
Это также создает почти идентичный код - некоторые метки и искаженные имена отличаются, как и следовало ожидать, но различия сгенерированного asm, созданного g++ -Wall -Wextra -S
(снимок 4.7), не имеют существенных различий. Компилятор в основном записывает все перегрузки, которые требуются вашей программе, на лету, а затем оптимизирует, как и раньше.
Следующий код, не являющийся шаблоном, также выдает почти идентичный результат:
#include <iostream>
#include <functional>
int main() {
double d;
int i;
d= -10; i=-10;
std::cout << "i=" << i << ", d=" << d << std::endl;
d= -10; i=-10;
std::cout << "i=" << i << ", d=" << d << std::endl;
}
Здесь снова единственные заметные различия — это метки и имена символов.
Дело в том, что современный компилятор может делать "что правильно" без особых хлопот в коде шаблона. Если то, что вы выражаете, является простым под всей механикой шаблона, результат будет простым. Если это не так, результат будет более существенным, но таким же был бы результат, если бы вы полностью избегали шаблонов.
Однако это становится интересным (на мой взгляд), вот что: все мои утверждения были дополнены чем-то вроде «с приличным современным компилятором». Если вы пишете шаблоны с переменным числом аргументов, вы можете быть почти уверены, что то, что вы используете для компиляции, является приличным современным компилятором. Никакие старые неуклюжие реликтовые компиляторы не поддерживают шаблоны с переменным числом аргументов.
person
Flexo
schedule
10.11.2011