如何在C++11中实现将多个任意长度整数序列作为非类型模板参数传入模板类?
实现C++11下的编译期整数序列模板参数
在C++11里确实没法直接把初始化列表{1,2,3}当成非类型模板参数传递,但我们可以用模板元编程的小技巧来实现类似的效果,核心思路是把整数序列封装成一个编译期的类型,再把这个类型作为模板参数传给Foo。下面是具体的实现方案:
方案一:用类型参数封装整数序列(推荐)
这种方式语法更接近你的需求,而且不需要额外定义全局变量,完全在编译期处理:
1. 定义序列封装模板
首先我们写一个可变参数模板,用来持有任意长度的整数序列,同时提供转成std::vector的方法:
#include <vector> using std::vector; // 封装任意长度整数序列的模板 template<int... Ints> struct IntSequence { // 编译期转成vector的静态方法 static vector<int> toVector() { return {Ints...}; } };
2. 修改Foo模板
让Foo接受两个IntSequence类型作为模板参数,在构造函数里直接调用序列的转vector方法:
void f(vector<int> const & vec1, vector<int> const & vec2) { // 这里写你的业务逻辑 } template<typename Seq1, typename Seq2> struct Foo { Foo(){ f(Seq1::toVector(), Seq2::toVector()); } };
3. 实例化写法
现在你可以这样实例化Foo,语法已经很接近你想要的形式了:
int main(){ Foo<IntSequence<1,2,3,4>, IntSequence<5,6,7>> foo; }
如果觉得IntSequence<...>有点繁琐,可以用宏来简化:
#define INT_SEQ(...) IntSequence<__VA_ARGS__> // 简化后的实例化 Foo<INT_SEQ(1,2,3,4), INT_SEQ(5,6,7)> foo;
方案二:用静态数组作为非类型模板参数
如果你坚持要用非类型模板参数(而不是类型参数),C++11支持将静态constexpr数组的指针作为非类型参数,但需要提前定义全局数组,语法会稍显繁琐:
#include <vector> using std::vector; void f(vector<int> const & vec1, vector<int> const & vec2) { // 业务逻辑 } // 提前定义全局的constexpr数组 constexpr int seq1[] = {1,2,3,4}; constexpr int seq2[] = {5,6,7}; // Foo模板接受数组指针和长度作为非类型参数 template<const int* Seq1, size_t Len1, const int* Seq2, size_t Len2> struct Foo { Foo(){ f(vector<int>(Seq1, Seq1 + Len1), vector<int>(Seq2, Seq2 + Len2)); } }; int main(){ Foo<seq1, sizeof(seq1)/sizeof(seq1[0]), seq2, sizeof(seq2)/sizeof(seq2[0])> foo; }
扩展:C++20的更简洁方案
如果你的项目可以升级到C20,那事情会简单很多——C20支持将std::array作为非类型模板参数,直接用初始化列表传递:
#include <vector> #include <array> using std::vector; using std::array; void f(vector<int> const & vec1, vector<int> const & vec2) { // 业务逻辑 } template<array<int, auto> Seq1, array<int, auto> Seq2> struct Foo { Foo(){ f(vector<int>(Seq1.begin(), Seq1.end()), vector<int>(Seq2.begin(), Seq2.end())); } }; int main(){ Foo<{{1,2,3,4}}, {{5,6,7}}> foo; }
内容的提问来源于stack exchange,提问作者nj16
相关产品推荐
相关产品推荐

