5

次のコードは、私が知っているように、「推測されたコンテキストではない」(またはそうでない) 必要があります。

template <class... X, class Y>
void f(X... args, Y y)
{

}

int main()
{
    f(12);
    f<int, int, int>(1, 2, 3, 4);
}

しかし、g++ 4.9 は in の両方のインスタンス化のためにそれをコンパイルしますf...main誰か説明できますか?

4

2 に答える 2

1

最初の呼び出しf(12)の形式が正しくありません。パラメーター宣言の最後に表示されないパラメーター パックは、[temp.deduct.type]/p5.7 による非推定コンテキストです。

非推定コンテキストは次のとおりです。

— [..]

parameter-declaration-listの末尾にない関数パラメーター パック

さらに [temp.deduct.call]/p1 で:

parameter-declaration-listの末尾にある関数パラメーター パックの場合A、呼び出しの残りの各引数の型が、関数パラメーター パックの declarator-id の型と比較されPます各比較は、関数パラメーター パックによって展開されたテンプレート パラメーター パック内の後続の位置のテンプレート引数を推測します。関数パラメーター パックが推定されないコンテキスト (14.8.2.5) に表示される場合、そのパラメーター パックの型は推定されません。

[ 例:

template<class ... Types> void f(Types& ...);
template<class T1, class ... Types> void g(T1, Types ...);
template<class T1, class ... Types> void g1(Types ..., T1);

void h(int x, float& y) {
    const int z = x;
    f(x, y, z); // Types is deduced to int, float, const int
    g(x, y, z); // T1 is deduced to int; Types is deduced to float, int
    g1(x, y, z); // error: Types is not deduced
    g1<int, int, int>(x, y, z); // OK, no deduction occurs
}

— 終了例 ]

したがって、パラメーター パックX...は関数の引数によって推測できず、テンプレート引数の推測は失敗します。GCC は、推測しない12ためにテンプレートを拒否するのではなく、最初の呼び出しを受け入れるため、バグのようです。

ただし、 2 番目の呼び出しはf<int, int, int>(1, 2, 3, 4)、[temp.deduct]/p6 に従って整形式です。明示的に指定されたテンプレート引数は、関数テンプレートのテンプレート パラメーターにすぐに置き換えられます。これはX = {int, int, int}. 次に、テンプレートの引数推定は、次Yのように右端の引数から推定されますint

テンプレート引数推定プロセスの特定の時点で、テンプレート パラメーターを利用する関数型を取得し、それらのテンプレート パラメーターを対応するテンプレート引数に置き換える必要があります。これは、明示的に指定されたテンプレート引数が関数型に代入されるときにテンプレート引数推定の開始時に行われ、デフォルト引数から推定または取得されたテンプレート引数が置換されるときにテンプレート引数推定の最後に再度行われます。

([temp.deduct]/p2):

少なくとも 1 つのパラメーターがテンプレート パラメーター pack でない限り、パラメーターよりも多くの引数があってはなりません。また、非パック パラメーターごとに引数が存在する必要があります。

Clang は最後の関数呼び出しを受け入れませんが、GCC は受け入れます。これは Clang のバグだと思います。


parameter-pack の発生に続く default-arguments の使用に関して、未解決のCWG 問題 1609があることに注意してください。そのコンテキストでの Clang の動作に異議を唱えるLLVM Bug 21774もあります。

于 2015-05-21T02:21:17.727 に答える