16

可変個引数テンプレートの世界への旅を続けると、別の問題に遭遇しました。

次のテンプレート クラスを想定します。

template < typename T >
struct foo 
{
    //default implementation
};

次のように、可変個引数テンプレートのインスタンス化に部分的に特化することができます。

template < template < typename ... > class T, typename ...Args >
struct foo< T< Args... > >
{
    //specialized implementation
};

これによりfoo< int >、デフォルトの実装とfoo< std::tuple< int, char > >特殊な実装に対応します。

ただし、複数のテンプレート パラメーターを使用すると、事態はさらに複雑になります。たとえば、次のテンプレート クラスがあるとします。

template < typename T, typename U >
struct bar {};

で行ったように、それを部分的に特化したいのですがfoo、それはできません。

template < template < typename ... > class T, typename ...TArgs,
           template < typename ... > class U, typename ...UArgs >
struct bar< T< TArgs... >, U< UArgs... > > {};

//This would correspond to the specialized version with
//T=std::tuple,
//TArgs=int,char
//U=std::tuple,
//UArgs=float
bar< std::tuple< int, char >, std::tuple< float > > b;

確かに、私が正しければ、テンプレート パラメーター パックは 1 つしか持てず、パラメーター リストの最後に配置する必要があります。テンプレート宣言でこれが必須である理由は理解していますが、特定の部分的なテンプレートの特殊化 (上記の例など) では、これは問題になりません。

複数のテンプレート パラメーター パックを使用して部分的なテンプレートの特殊化を実現することは可能ですか?


編集:今、私はばかげていると感じています...上記のコードは完全にコンパイルされます(少なくともgcc 4.5では)。コンパイル エラーは、複数のパラメーター パックが原因ではなく、メンバー関数のパラメーターとして使用されたことが原因でした。の部分的な特殊化で、とパラメータbarの両方を受け取るメンバー関数を定義しようとしました。TArgsUArgs

template < template < typename ... > class T, typename ...TArgs, 
           template < typename ... > class U, typename ...UArgs >
struct bar< T< TArgs... >, U< UArgs... > >
{
    void method( TArgs... targs, UArgs... uargs ) //compile error here
    {
    }
};

メンバー関数の宣言で、gcc がエラーを表示します

パラメータ パックは、パラメータ リストの最後にある必要があります。

私が知る限り、コンパイラは、特定のテンプレートのインスタンス化に対して正しいメンバー関数を定義できるはずです。たとえばbar< std::tuple< int, char >, std::tuple< float > >、メンバー関数を含める必要がありますvoid method( int, char, float )。私は何か間違ったことをしていますか?それとも、不可能なことをしようとしていますか? もしそうなら、これが不可能な正当な理由はありますか?

4

1 に答える 1

6

おそらく、この回答はあなたの質問を直接解決するものではありませんが、テストしたときに次のコードを ideone(gcc-4.5.1) でコンパイルしました。

#include <cstdio>
#include <tuple>

template< class, class > struct S {
  S() { puts("primary"); }
};

template<
  template< class... > class T, class...TArgs
, template< class... > class U, class...UArgs
>
struct S< T< TArgs... >, U< UArgs... > > {
  S() { puts("specialized"); }
};

int main()
{
  S< int, int >  p;                                       // "primary"
  S< std::tuple< int, char >, std::tuple< float > >  s;   // "specialised"
}

このコードが厳密に準拠しているかどうかはわかりませんが、N3225 14.5.3 を読んだ限りでは、テンプレート パラメーター パックが最後のテンプレート パラメーターでなければならないという記述は見つかりませんでした。

編集:
N3225 を読み直したところ、次のステートメントが見つかりました。

8.3.5/4 parameter-declaration-clause が省略記号または関数パラメーター パック (14.5.3) で終了する場合、引数の数は、既定の引数を持たないパラメーターの数以上である必要があります。関数パラメーター パックではありません。

14.8.2.5/10 [注: 関数パラメーター パックは、パラメーター宣言リスト (8.3.5) の最後でのみ発生できます。-エンドノート]

したがって、おっしゃったように、関数パラメーター pack は残念ながら最後のパラメーターでなければなりません。
クラス テンプレートの非テンプレート メンバー関数は、インスタンス化された (完全に特殊化された) 場合、そのクラスの通常の関数です。したがって、この質問のコードを特別なケースとして論理的にコンパイルできることを願っています。

于 2011-01-16T18:21:12.557 に答える