我有一个类Foo
需要有可变数量的模板参数,但这些参数需要是某种泛型类型,而不是完全任意的。 E.g
template < int I, typename T> struct Arg;
using type1 = Foo<Arg<3, double>>;
using type2 = Foo<Arg<1, int>, Arg<7, float>, Arg<1, int>>;
我想知道实现这一目标的最佳途径是什么。我想我需要首先使用简单的可变参数模板
template < typename ...T >
class Foo;
从那里,我可以遵循递归的道路
template < int I, typename T, typename ...Others>
template Foo<Arg<I, T>, Others...>
{
...
};
但是this answer对另一个问题的解读让我想知道我对可变参数模板的了解以及有时如何避免递归。
我的问题是,模板参数是否应该采用相对严格的格式,这样才能实现Foo
的部分特化,这种特殊化不会是递归的,并且可以有效地处理所有Foo
形式Foo<Arg<...>,Arg<...>,...>
?
答案 0 :(得分:6)
这有效:
#include <iostream>
template <int i, typename T> struct Arg;
template <typename ...T>
class Foo;
template <int ...Is, typename ...Ts>
class Foo<Arg<Is, Ts>...>
{
public:
static constexpr unsigned int N = sizeof...(Is);
};
int main()
{
using type2 = Foo<Arg<1, int>, Arg<7, float>, Arg<1, int>>;
std::cout << type2::N << "\n";
}
虽然使用该表单中的模板参数可能或者可能不容易或不方便,但取决于您要对它们执行的操作。
答案 1 :(得分:2)
您可以使用SFINAE执行此操作。这是一幅草图:
template<class...Bs>
constexpr bool is_all_true(Bs...); // write this
template<class T>
constexpr bool is_valid_arg(); // write this
template < class=void, class...Ts >
class FooImpl;
template < class...Ts >
class FooImpl<std::enable_if_t<is_all_true( is_valid_arg<Ts>()...) >, Ts...> {
// code
};
template<class...Ts>
class Foo:FooImpl<void, Ts...> {};
现在Foo
是FooImpl
,用于测试是否满足您的先决条件。
您必须撰写is_all_true
和is_valid_arg
,其中is_valid_arg
会测试T
的格式是Arg<int, Type>
。
例如,在C ++ 17中,is_all_true
只是return (true && ... && bs);
(如果我没记错的话true
是多余的,但为了清晰起见我喜欢它)。在C ++ 11/14中,它会更难。