简体   繁体   English

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

[英]Variadic template partial specialization of a class to restrict type of template arguments

I have a class Foo that needs to have a variable number of template arguments, but these arguments need to be of a certain generic type, as opposed to being completely arbitrary. 我有一个类Foo需要有可变数量的模板参数,但这些参数需要是某种泛型类型,而不是完全任意的。 Eg 例如

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>>;

I am wondering what would be the best way to achieve this. 我想知道实现这一目标的最佳方法是什么。 I guess I need to start first with a plain variadic template 我想我需要首先使用简单的可变参数模板

template < typename ...T >
class Foo;

From there, I could follow the recursive road 从那里,我可以沿着递归的道路前进

template < int I, typename T, typename ...Others>
template Foo<Arg<I, T>, Others...>
{
    ...
};

but the reading of this answer to another question left me wonder about my knowledge of variadic templates and how recursion can sometimes be avoided. 但是对另一个问题的这个答案的阅读让我想知道我对可变参数模板的了解以及有时如何避免递归。

My question is, does the fact that the template arguments are expected to be in a relatively rigid format enable a partial specialization of Foo that would not be recursive, and that would effectively handle all Foo s of the form Foo<Arg<...>,Arg<...>,...> ? 我的问题是,模板参数是否需要采用相对严格的格式才能实现Foo的部分特化,这种特殊化不会是递归的,并且可以有效地处理Foo<Arg<...>,Arg<...>,...>形式的所有Foo Foo<Arg<...>,Arg<...>,...>

This works: 这有效:

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

Though it might or might not be easy or convenient to use the template arguments in that form, depending on what you want to do with them. 虽然在该表单中使用模板参数可能会或可能不容易或不方便,具体取决于您要对它们执行的操作。

You can do this with SFINAE. 你可以用SFINAE做到这一点。 Here is a sketch: 这是一个草图:

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

now Foo is a FooImpl , which tests if your preconditions are all met. 现在Foo是一个FooImpl ,它测试你的前提条件是否都满足。

You do have to write is_all_true and is_valid_arg , where is_valid_arg tests if T is of the form Arg<int, Type> . 你必须编写is_all_trueis_valid_arg ,其中is_valid_arg测试T的形式是否为Arg<int, Type>

As an example, in C++17, is_all_true is just return (true && ... && bs); 例如,在C ++ 17中, is_all_true只是return (true && ... && bs); (The true is redundant if I remember rightly, but I like it for clarity). (如果我没记错的话, true是多余的,但为了清楚起见,我喜欢它)。 In C++11/14 it will be harder. 在C ++ 11/14中,它会更难。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM