2016-08-08 1 views
9

私はいくつかの興味深いバリデーショナルなテンプレート関数の動作に出くわしました。誰もがこれを定義する標準の関連ルールを指摘できますか?非末尾のパラメータパックの動作に戸惑う

GCC,ICCおよびMSVCは、次のコードを正常にコンパイルします(Clangはそうではありませんが、これはコンパイラのバグによるものです)。 fooにこの呼び出しで

template<class A, class... Bs, class C> 
void foo(A, Bs..., C) { } 

int main() 
{ 
    foo<int, int, int, int>(1, 2, 3, 4, 5); 
} 

テンプレート引数がABsのために提供され、その後、Cintなると推定されます。

しかし、我々は単に最後の二つのテンプレートパラメータを反転場合:

template<class A, class C, class... Bs> 
void foo(A, Bs..., C) { } 

その後allthreecompilersスローエラーを。ここではGCCからのいずれかになります。

main.cpp: In function 'int main()': 
main.cpp:8:42: error: no matching function for call to 'foo(int, int, int, int, int)' 
    foo<int, int, int, int>(1, 2, 3, 4, 5); 
             ^
main.cpp:4:6: note: candidate: template<class A, class C, class ... Bs> void foo(A, Bs ..., C) 
void foo(A, Bs..., C) { } 
     ^~~ 
main.cpp:4:6: note: template argument deduction/substitution failed: 
main.cpp:8:42: note: candidate expects 4 arguments, 5 provided 
    foo<int, int, int, int>(1, 2, 3, 4, 5); 
            ^

物事をより面白くするために、最初のfooためinvalidであり、第二のためvalidのみ四つの引数で呼び出します。

第二に、Cを明示的に供給されなければならないのに対しfooCの最初のバージョンで、推測しなければならないようです。

標準のどの規則でこの動作が定義されていますか?

+3

最初の例は、コンパイルしたものではありません。それは不公平です。 –

+0

@SamVarshavchik理由を説明できますか? – TartanLlama

+0

テンプレートは4つのパラメータで明示的にインスタンス化されています。テンプレートは、パラメータと同じパラメータを関数呼び出しに展開します。関数呼び出しには4つのパラメータが必要です。 4つのパラメータを必要とする関数呼び出しに5つの実際のパラメータを渡すと、不正な形式になります。 –

答えて

2

よくあることですが、質問を投稿してから数時間後に回答が届きました。

template<class A, class... Bs, class C> 
void foo1(A, Bs..., C) { } 

template<class A, class C, class... Bs> 
void foo2(A, Bs..., C) { } 

及び(foofoo1又はfoo2であると仮定して)次の呼び出し:

fooの2つのバージョンを検討

foo<int,int,int,int>(1,2,3,4,5); 

foo1の場合には、テンプレートパラメータは以下のように取得され次のとおりです。

A = int (explicitly provided) 
Bs = {int,int,int} (explicitly provided) 
C = int (deduced) 

しかし、彼らはこのようになりfoo2の場合は210:

A = int (explicitly provided) 
C = int (explicitly provided) 
Bs = {int,int} (explicitly provided) 

Bsは非推測コンテキスト([temp.deduct.type]/5.7)であるので、任意の更なる関数の引数は、パックを拡張するために使用することはできません。そのように、foo2は明示的に提供されるすべてのテンプレート引数を持つ必要があります。

+0

短いストーリー:非末尾のバリデーションテンプレートパックを混乱させないでください。あなたが何をしているのか分からない限り。これはC++のすべてに対して有効なステートメントです。 – rubenvb