2016-03-29 10 views
8

次のコード:可変長引数を使って部分的な特殊で打ち鳴らす行動対GCCプラス同じ種類の追加の引数

#include <cstddef> 

template <size_t N, 
      typename T, 
      T first, 
      T... rest> 
struct A { 
}; 

template<typename T, 
     T... args> 
struct A<0, T, args...> { 
}; 

int main() { 
    A<0, int, 1> a0; 
    A<2, int, 1, 2> a2; 
    return 0; 
} 

...が原因にg++(バージョン5.1.05.3.0)でコンパイルされません。

error: partial specialization is not more specialized than the primary template because it replaces multiple parameters with a pack expansion

...しかしclangでコンパイル。

は、そのような部分的な特殊化を宣言することができますか?

サイドノート:実際には、A<0, int>は両方のコンパイラ(テンプレート引数が間違っている)でコンパイルできないため、実際には特殊化は危険です。

+0

'<0, int>は'、あなたが最初のテンプレートを変更する必要ができるようにします。それは専門化のためには遅すぎる。 – Jarod42

+0

@ Jarod42はい、私はテンプレートのインスタンス化が間違っていることを知っています。私は 'T ... args'だけ' g ++ 'ではエラーを発生させ、' clang'ではエラーを発生させない部分的な特殊化について尋ねています。それはより明白です)。 – Holt

+2

GCCが正しいです。これは[DR 1495](http://wg21.link/cwg1495)(GCCの管理者によって報告されているのでやや意外である)によれば、不正な形式です。 –

答えて

8

gccが専門で、実際に、より特化していないため、コードが悪い形成され、正しいです。

Within the argument list of a class template partial specialization, the following restrictions apply: [...] The specialization shall be more specialized than the primary template (14.5.5.2).

ことを決定するために、我々はだろう:[temp.class.spec](リンクのためのH/TがTC、DR 1495の結果として)であるから


ルール、 2つを合成関数テンプレートとして書き換えます。

template <size_t N, class T, T first, T... rest> 
void __f(A<N, T, first, rest...>); // primary 

template <class T, T... args> 
void __f(A<0, T, args...>);   // specialization 

次に、部分的な順序付けルールを実行します。これには、各テンプレートパラメータの新しいタイプ/値を合成し、いずれの方向にも控除が成功するかどうかを確認することが含まれます。

N0のため)確かに、特殊化の控除はプライマリで失敗します。他の方向では、[temp.deduct.partial]から:

If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails.

私たちはパックに対してT firstを推測しようとしているので、控除もこの方向に失敗します。これは、合成された関数テンプレートのどちらも他よりも特殊化されていないことを意味します。つまり、クラステンプレートの特殊化はプライマリテンプレートよりも特殊化されていません。したがって、gccは拒否するのが正しいでしょう。

0

は考慮してください。

template <class T, T first, T... rest> 
struct X{}; 

template<class T, T... rest> 
struct X<T, rest...>{}; 

まったく同じエラー。 firstrestパックの最初の要素と解釈できるため、そのような特殊化に違いはありません。特殊化 - ウェルにfirstを追加すると、これがプライマリテンプレートです。あなたがfirstを追加することができますが、あなたの専門分野で:

//specialization 
template<typename T, 
     T first, 
     T... args> 
struct A<0, T, first, args...> { 
}; 
関連する問題