最近、このサンプルコードを作成して、C++11可変個引数テンプレート関数の使用法を説明しました。
template <typename Head, typename... Tail> void foo (Head, Tail...);
template <typename... Tail> void foo (int, Tail...);
void foo () {}
template <typename... Tail>
void foo (int x, Tail... tail)
{
std :: cout << "int:" << x;
foo (tail...);
}
template <typename Head, typename... Tail>
void foo (Head x, Tail... tail)
{
std :: cout << " ?:" << x;
foo (tail...);
}
foo (int (123), float (123)); // Prints "int:123 ?:123.0"
前方宣言する最初の2行をfoo
省略すると、int:123int:123
代わりにこれが出力されます。これは、特定の経験豊富で知識豊富なC++プログラマーを驚かせました。
彼は、2フェーズルックアップの第2フェーズまでボディがインスタンス化されないため、前方宣言は必要ないと確信していました。彼は、コンパイラ(gcc 4.6)にバグがあると考えています。
foo
2つは異なるベーステンプレート関数であり、ベーステンプレートの選択は最初のフェーズでロックインする必要があるため、コンパイラは正しいと思います。そうしないと、foo
すべてのバージョンが定義される前にインスタンス化することで、単一定義規則に違反する可能性があります。そしてその後も(リンカが冗長なテンプレート関数定義が同一で、交換可能で、破棄可能であるとどのように想定するかを検討してください)。
それで、誰が正しいのですか?
上記のリンクされたGOTWは、関数テンプレートが部分的に特殊化されない方法と理由をうまく説明していますが、可変個引数テンプレート関数の存在は混乱を助長しているようです-foo<int,Tail...>
部分的に特殊化されるべきfoo<Head,Tail...>
直感は、非少なくとも私にとっては、可変個引数関数。