例えば次のようなクラステンプレートX、Yがあったとする。
template <class> struct X {}; template <class, class> struct Y {};
Xはテンプレート引数が1個、Yはテンプレート引数が2個である。
このX、Yを次のようなクラステンプレートに与えてみる。このXorYは、与えられたXやYのテンプレート引数の数を知ることはできるのだろうか。
template <template <class...A> class T> struct XorY { //static constexpr size_t NumOfTArgs = sizeof...(A);これは不可能。 }; //XorY<X>::NumOfTArgs == 1; //XorY<Y>::NumOfTArgs == 2; //であってほしい。
テンプレート引数の数はXなら1個、Yなら2個であるが、XorYのテンプレートテンプレートパラメータは可変長であるため、そのままでは分からない。
色々と悩んだが、次のようにconstexprな関数のオーバーロードで解決する方法しか思いつかなかった。
template <template <class> class T> constexpr size_t NumOfTArgs() { return 1; } template <template <class, class> class T> constexpr size_t NumOfTArgs() { return 2; } template <template <class...> class T> struct XorY { static constexpr size_t NumOfTArgs = NumOfTArgs<T>(); };
次のような部分特殊化ができないかとも思ったが、どうやら不可能なようだ。
template <template <class...> class T> struct NumOfTArgs; template <template <class> class T> struct NumOfTArgs<T> { static constexpr size_t value = 1; }; template <template <class, class> class T> struct NumOfTArgs<T> { static constexpr size_t value = 2; }; //プライマリテンプレートの仮引数Tと2個の部分特殊化の引数Tとが一致してしまっているためコンパイルエラー。
テンプレートテンプレートパラメータは不可欠な機能であるが、ちょっと不便な所も多い印象だ。非型テンプレート引数にautoを使えないC++14以前だと融通が効かないのでしばしば苦労するし、上のXorYに非テンプレートなクラスを渡せないのも面倒だ。通常の可変長引数テンプレートは引数0個が許されるのに、テンプレートテンプレートパラメータでは許されないという厄介さ。何とかならないものだろうか。