複数のテンプレートパラメーターパックを使用した部分的なテンプレートの専門化
-
11-10-2019 - |
質問
継続 バリアーディックテンプレートの世界への私の旅, 、別の問題に遭遇しました。
次のテンプレートクラスを仮定します。
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
, 、両方を取るメンバー関数を定義しようとしました TArgs
と UArgs
パラメーター:
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 )
. 。私は何か間違ったことをしていますか?それとも私は不可能なことをしようとしていますか?もしそうなら、これが不可能な理由は正当な理由がありますか?
解決
おそらく、この答えはあなたの質問を直接明確にすることはありませんが、私がテストしたときに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パラメーター除去条項が省略記号または関数パラメーターパック(14.5.3)で終了する場合、引数の数は、デフォルトの引数を持たないパラメーターの数と等しく、関数パラメーターパックではありません。
14.8.2.5/10 [注:関数パラメーターパックは、パラメーター決定リスト(8.3.5)の最後にのみ発生します。 -ENDノート
したがって、あなたが言ったように、残念ながら関数パラメーターパックは最後のパラメーターでなければなりません。
クラステンプレートのテンプレート以外のメンバー関数は、インスタンス化された場合のクラスの通常の関数です(完全に専門化されています)。したがって、この質問のコードを、特別なケースとして論理的にコンパイルできることを願っています。