簡単に言えば、「使用した分だけ支払う」という原則は、以前とまったく同じように適用されます。
より長い答えは、2 つの仮想実装で生成されたコードを比較することで確認できます。
#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;
}
g++ -Wall -Wextra -Sこれもほとんど同じコードを生成します - 予想通りラベルとマングルされた名前の一部が異なりますが、 (4.7 スナップショット)によって生成された生成された asm の diff には大きな違いはありません。コンパイラは基本的に、プログラムが必要とするすべてのオーバーロードをオンザフライで記述し、以前と同様に最適化します。
次の非テンプレート コードも、ほぼ同じ出力を生成します。
#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;
}
ここでも、顕著な違いはラベルとシンボル名だけです。
要点は、最新のコンパイラは、テンプレート コードであまり手間をかけずに「正しいこと」を実行できるということです。すべてのテンプレート メカニクスの下で表現しているものがシンプルであれば、出力はシンプルになります。そうでない場合、出力はより実質的になりますが、テンプレートを完全に回避した場合の出力も同様になります。
ただし、これが興味深いのは(私の見解では)これです。私のステートメントはすべて、「適切な最新のコンパイラを使用して」のようなもので修飾されていました。可変個引数テンプレートを作成している場合、コンパイルに使用しているものはまともな最新のコンパイラであることはほぼ確実です。不格好な古い遺物のコンパイラは、可変個引数テンプレートをサポートしていません。