【发布时间】:2021-10-04 15:56:02
【问题描述】:
我的 c++ 项目中有几段代码如下所示:
system<0>::global_instance.do_something();
system<1>::global_instance.do_something();
system<2>::global_instance.do_something();
system<3>::global_instance.do_something();
//...
system<29>::global_instance.do_something();
system<30>::global_instance.do_something();
system<31>::global_instance.do_something();
这似乎有点重复,对吧?如果我能做这样的事情就好了:
for(int i = 0; i < 32; i++)
{
system<i>::global_instance.do_something();
}
很遗憾,这不起作用,因为i 的值在编译时是未知的,因此不能用作system 的模板参数。
我需要的是一种在编译时展开或展开循环的方法。
我见过一些使用模板来实现展开的实现,但它们不适用于我想要做的事情。理想情况下,循环展开将在预处理期间进行,并且可以将任意语句作为输入。
例如,这个:
#unroll NUM 0 5
foo<NUM>();
#endunroll
会被翻译成这样:
foo<0>();
foo<1>();
foo<2>();
foo<3>();
foo<4>();
foo<5>();
还有这个:
#unroll NUM 0 5
blah blah blah NUM
#endunroll
会被翻译成这样:
blah blah blah 0
blah blah blah 1
blah blah blah 2
blah blah blah 3
blah blah blah 4
blah blah blah 5
即使blah blah blah NUM 是一个语法错误的语句,它仍应被复制,并且令牌 NUM 的每个实例都应替换为适当的数值。
有没有办法在 vanilla c++ 中实现这一点?或者是否有任何特殊的 c++ 编译器可以添加此功能?
编辑:我在 cmets 中找到了来自 @HTNW 的答案。
#include <iostream>
using namespace std;
template<auto begin, auto end>
inline void unroll(auto f)
{
if constexpr(begin < end)
{
f.template operator()<begin>();
unroll<begin + 1, end>(f);
}
}
template<int NUM>
struct thingy
{
static void print(){cout << NUM << endl;}
};
int main()
{
unroll<0,8>([]<int i>()
{
thingy<i>::print();
});
}
输出:
0
1
2
3
4
5
6
7
完成这项工作的行是f.template operator()<begin>();。我不知道这条线是什么意思,而且我以前从未见过它。如果有人能给我解释一下,那就太好了。
【问题讨论】:
标签: c++ metaprogramming template-meta-programming