2016-07-28 12 views
6

次のコードはコンパイルしてokを実行します。ファンクションテンプレートパラメータパックがパラメータリストの末尾にない

void foo() { 

} 

template <typename T, typename... Args> 
void foo(T x, Args... args) { 
    cout << x << endl; 
    foo(args...); 
} 

// inside main() 
foo(1,1,1); 

この他のコードはコンパイルされません:

void foo() { 

} 

template <typename... Args, typename T> 
void foo(Args... args, T x) { 
    foo(args...); 
    cout << x << endl; 
} 

// inside main() 
foo(1,1,1); 

コンパイラは、一致する関数がfoo(1,1,1)への呼び出しのために存在しないことを言うと、foo(Args... args, T x)が候補ですが、テンプレート引数控除/置換が失敗したことを言います候補者は1つの議論を期待しているが、3つは提供されているからだ。

この状況では、コンパイラが処理できない曖昧さはありますか?このコンパイルエラーはちょうど私に不合理なようです。たぶんこれはC++標準に合致していないのでしょうか?

答えて

5

Clang's error messageから興味深い部分は次のとおりです。

main.cpp:11:6: note: candidate template ignored: couldn't infer template argument 'T' 

void foo(Args... args, T x) { 
    ^

問題は、パラメータパックArgs...Tを発生することです。

Args...は "greedy"なので、コンパイラがTを推測するためのパラメータが残っていないため、失敗します。関数テンプレートのテンプレートパラメータパックは別のテンプレートパラメータによって に続いてはならない

[temp.param]/11

:標準(強調鉱山)を引用

であり、そのテンプレートパラメータは、 であり、関数テンプレートのparameter-type-listからを導出しないか、または デフォルト引数を持ちます。 [例:

... 
// U can be neither deduced from the parameter-type-list nor specified 
template<class... T, class... U> void f() { } // error 
template<class... T, class U> void g() { } // error 

- 終了例]

+0

これは単に "標準を正しく実装していないコンパイラ"の状況ですか? – matheuscscp

+0

@matheuscscp、いいえ、標準でも許可されていません。 – chris

+0

ありがとう! – matheuscscp

3

@JohannesSchaub-litb's commentsに基づいて回答)

規格によれば、関数パラメータパックで使用される場合、テンプレートパラメータパックが演繹ありませんパラメータリストの最後ではありません。

$14.8.2.1/1 Deducing template arguments from a function call [temp.deduct.call]

関数パラメータパックは非推測コンテキスト ([temp.deduct.type])に表示されたら、そのパラメータパックの種類を推定 ことはありません。[例:

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

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

- 終了例]

および非推測コンテキスト、$14.8.2.5/5 Deducing template arguments from a type [temp.deduct.type]約:

PARAMETER-の終了時に発生していない関数パラメータパック宣言リスト。

だから失敗したfoo(1,1,1);の直接の理由は、テンプレートパラメータArgsは、機能が有効に呼び出すようにする必要があるこれ、推測されていないということです。

エラーメッセージを説明するために、推測されないテンプレートパラメータパックは、テンプレート引数[1]の空のシーケンスに導かれます。省略されることを意味します。その後、引数の数が一致しないのでfoo(1,1,1);が失敗しました。これはコンパイラが苦情を申し立てたものです。

テンプレートの引数を明示的に指定して、コードの元の意図を満たしていなくても、タイプ控除を避けることができます。など:

template <typename T, typename... Args> 
void foo(Args... args, T x) { 
} 

int main() { 
    // inside main() 
    foo<int, int, int>(1, 1, 1); 
} 

Hereのいくつかの追加情報です。


[1]私は標準についてこれについて直接的な表現を見つけることはできません。最も近いものはthisです。それ以外の場合は推定されない後続のテンプレートパラメータパック([temp.variadic])は、テンプレート引数の空のシーケンスに導かれます。

関連する問題