2016-09-25 1 views
1

[temp.variadic](作業草案)から、別のテンプレートクラスまたは関数の引数リストを定義しながら、パラメータパックを展開することができました。パラメータパックを展開し、引数リストを定義することはできますか?

は、次のクラスを考えてみましょう:

template<typename... T> 
struct S { 
    template<T... I> 
    void m() {} 
}; 

int main() { 
    S<int, char> s; 
    // ... 
} 

意図がキャプチャにテンプレートクラスSを専門とメンバーメソッドの非型パラメータの引数リストを定義するためにそれらを使用するために使用さタイプですmTは数種類に限られますが、これは質問の議論ではありません)。

この法的コードはありますか?私はそれを使用した方法でパラメータパックを使うことができますか、私は標準を誤解していますか(確かにそうだと確信しています)?

  • s.m<0, 'c'>():ここで、質問に詳細を追加するために


    は、主要なコンパイラといくつかの実験からのいくつかの結果であるclang v3.9は、GCC v6.2それをコンパイルし、エラーを返しGCC v7

  • s.m<0>();clang v3.9はエラーを返し、GCC v7はICEでコンパイルを停止しGCC v6.2、それをコンパイルします。

  • s.m<>();clang v3.9,およびGCC v7エラーなしでコンパイルします。

少なくとも、コンパイラは私と同じように混乱しているようです。

+0

はい、有効であり、空でもあります。https://stackoverflow.com/questions/32540178/what-c​​an-you-do-with-templates-with-zero-template-parameters –

+0

GCCは驚くほどあまり良くありませんvariadicテンプレートに関してはスマートです。 – DeiDei

+0

@ JohannesSchaub-litb 's.m <0>();'は拒否されるべきですか?どちらのコンパイラにもエラーがありますか? – skypjack

答えて

2

テンプレートSの定義、およびインスタンス化S<int, char>が有効です。

[temp.param]/15参照:「タイプ一つ以上の非拡張パラメータパックを含んパラメータ宣言あるテンプレートパラメータパックは、パックの拡張です。」

これはtemplate<T ...I>は、2つの異なるものの一つを意味することができますことを意味しますTは、非パックタイプであれば、それはTの任意の数を受け入れ、通常のパラメータパックを宣言します。しかし、Tに拡張されていないパラメータパックが含まれている場合、外側のテンプレートがインスタンス化されるときにパラメータ宣言が一連のパラメータに展開されます。

mへのあなたの最初の呼び出しは有効ですが、mにあなたの第二と第三の呼び出しは

S<int, char>のインスタンス化が次のようになります悪い形成されている:

template<> 
struct S<int, char> { 
    template<int I$0, char I$1> 
    void m() {} 
}; 

(どこI$0I$1をパックの最初と2番目のスライスはIです)。したがって

I$0I$1どちらも呼び出しからmに推論することができるので)、s.m<0,'c'>()は有効ですが、s.m<0>()s.m<>()が悪い形成されています。

+0

私はすでに両方のコンパイラに問題を開いており、ほぼ同じ詳細を与えています。ありがとうございました。 [this](http://stackoverflow.com/questions/39665300/gcc-vs-clang-variadic-template-and-pointers-to-member-methods)の質問にも同じことが適用されますか? – skypjack

+0

完全性のために、[ここ](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77731)はGCCと[ここ](https://llvm.org/bugs/show_bug)の問題です。 cgi?id = 30518)はclangするものです。必要に応じて詳細を追加してください。あなたは議論に関して私よりはるかに熟練しています! – skypjack

+0

お返事ありがとうございます。パックが展開された後、私はパックがもうパラメータパックではないと思います。しかし、メンバ関数 'f'では' t ... 'と言うことができます。その時点で 'T'が既に展開されていて、メンバ関数のテンプレートの特殊化は' void f( pack) 'の代わりに' void f(int t) 'のようになっていなければなりません。私は、関数のパラメータパックのインスタンス化/展開は一連のパラメータを生成すると私は考えていました。 –

関連する問題