Variadic模板部分特化的类,用于限制模板参数的类型

时间:2017-07-16 16:24:24

标签: c++ variadic-templates

我有一个类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<...>,...>

2 个答案:

答案 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...> {};

现在FooFooImpl,用于测试是否满足您的先决条件。

您必须撰写is_all_trueis_valid_arg,其中is_valid_arg会测试T的格式是Arg<int, Type>

例如,在C ++ 17中,is_all_true只是return (true && ... && bs);(如果我没记错的话true是多余的,但为了清晰起见我喜欢它)。在C ++ 11/14中,它会更难。