提取参数包

时间:2018-12-08 16:30:42

标签: c++

我想编写一个带有N类型的T自变量的函数。用例是在带有初始化列表的类中初始化数组。

Vector<uint8_t, 3> vector {5, 4, 3} 
Vector<uint16_t, 2> vector2 {90, 7}

我之所以不使用std::initalizer列表,是因为对于我开发的平台,没有标准库可用。因此,我尝试了一种使用自制integer_list的方法(类似于std中的方法)。

template <uint8_t ... Ints >
class IndexSequence {};

这很好用(Arraystd::array类似):

template <typename T, uint8_t I>
using ParamPack = T;

template <typename T, uint8_t N, typename I = makeIndexSequence<N>>
class Test;

template <typename T, uint8_t N, uint8_t... I>
class Test<T, N, IndexSequence<I...>> {

public:
 Test(ParamPack<T, I>... v)
 : data {v...} {}
private:
 Array<T,N> data;
};

但是我不喜欢这个“技巧”那么多地从integerSequece中提取整数参数包,因为整数参数包现在是类模板的一部分。实际上,我更喜欢仅在构造函数的模板中使用它,甚至不需要任何模板。

例如这样的东西:

Test(ParamPack<T, makeIndexSequence<N>.getParamPack()>... v)

或类似的东西。我认为这样会更清洁。 有没有什么方法可以将integerSequence中的Param Pack提取出来,而无需在类模板中包含param pack?

我试图对函数模板使用相同的技巧。不幸的是,它无法正常工作,因为功能不能部分专门化。

也许您甚至有一种完全不同的方法来拥有类似std::initializer_list或特定类型的Param包(我知道有可能只使用可变参数模板并将其转换为T,但是我想如果有更好的解决方案,可以避免这种情况。

1 个答案:

答案 0 :(得分:0)

为什么要避免使用可变参数模板?它们是解决此类问题的正确方法。

没有简单的方法可以从静态值N生成动态数量的参数。所有解决方案都涉及对某种可变参数输入的专门化(std::index_sequence的功能完全相同,它会生成可变参数模板参数。)

我认为,最优雅的方法是使用可变参数模板并使用static_assert保护输入。

template <typename T, size_t N>
class Test {
 public:
  template <typename... Ts>
  Test(Ts&&... v) : data{std::forward<Ts>(v)...} {
    static_assert(sizeof...(Ts) == N, "invalid number of arguments");
    static_assert((std::is_same_v<T, Ts> && ...), "wrong type");
  }

 private:
  std::array<T, N> data;
};

请注意,在此示例中,我正在使用std::array。当您传递无效的类型或无效数量的参数时,它将无法编译。

Test<int, 2> a{1, 2}; // compiles
Test<int, 2> b{1}; // invalid number of arguments
Test<int, 2> c{1, 2, 3}; // invalid number of arguments
Test<int, 2> d{1, 2.f}; // wrong type