我想编写一个带有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 {};
这很好用(Array
与std::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,但是我想如果有更好的解决方案,可以避免这种情况。
答案 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