类的可变参数模板部分专用化,用于限制模板参数的类型

Variadic template partial specialization of a class to restrict type of template arguments

本文关键字:参数 用于 类型 变参 板部 专用      更新时间:2023-10-16

我有一个类Foo需要具有可变数量的模板参数,但这些参数必须是某种泛型类型,而不是完全任意的。例如

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

但是阅读另一个问题的答案让我想知道我对可变参数模板的了解以及如何有时避免递归。

我的问题是,模板参数应该采用相对严格的格式这一事实是否能够实现Foo的部分特化,这不会是递归的,并且可以有效地处理形式Foo<Arg<...>,Arg<...>,...>的所有Foo

这有效:

#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";
}

尽管以这种形式使用模板参数可能容易或不方便,具体取决于您要对它们执行的操作。

你可以用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_trueis_valid_arg,其中is_valid_arg测试T是否是Arg<int, Type>的形式。

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