【发布时间】:2016-04-04 19:09:22
【问题描述】:
我正在尝试使用模板元编程来进行 N 维嵌套的金属循环。 嵌套部分很简单,但是将所有任意数量的迭代索引作为模板参数传递给最内层循环似乎有问题。
一个简单的未嵌套金属循环如下所示:
template <size_t I, size_t N>
struct meta_for
{
template <typename Lambda>
inline meta_for(Lambda &&iteration)
{
iteration(I);
meta_for<I+1, N> next(static_cast<Lambda&&>(iteration));
}
};
template <size_t N>
struct meta_for<N, N>
{
template <typename Lambda>
inline meta_for(Lambda &&iteration)
{
return;
}
};
#include <iostream>
int main()
{
meta_for<0, 10>([&](size_t i) // perform 10 iterations
{
std::cout << i << '\n';
});
return 0;
}
现在,我想制作一个金属循环,它接受一个表示维度(嵌套级别)的 N 参数,使用如下:
#include <iostream>
int main()
{
// perform 3 dimensionally nested iterations
// each index goes from 0 to 10
// so 10x10x10 iterations performed
meta_for<3, 0, 10>([&](size_t i, size_t j, size_t k)
{
std::cout << i << ' ' << j << ' ' << k << '\n';
});
return 0;
}
【问题讨论】:
-
[OT]:更喜欢
std::forward<Lambda>而不是static_cast<Lambda&&> -
@Jarod42:不,我讨厌 std::forward 有多种原因。 1:实际上它执行一个演员,但它的名字并没有反映这一点。 2:如果使用 std::forward 而不是普通转换,某些编译器(如 MSVC 14)会生成附加指令和/或无法对 lambda 执行优化。它可能会导致严重的性能问题。也许这是一个错误,也许不是,简单的演员表对我来说更加清晰和安全。我还为它制作了一个自定义的类似 C++11 的 forward_cast 函数。
-
在您的示例中,您可以从
0..10*10*10线性化您的索引,并用模数重新计算每个部分。见Completely enumerate indices of D-dimensional array at compile time -
好吧,我想这不是重复的,但无论如何我用“metaloops”做了一次非常相似的事情,我认为我的模板代码相当干净:stackoverflow.com/questions/32320753/…
-
所以,对于一些解释,我的想法是,而不是试图完全模仿
N嵌套循环的语义,我只是实现任意数量的类型列表的笛卡尔积,然后有一个笛卡尔积结果的单循环。对于运行时代码,这将需要更多内存,这不是一个好主意。但是对于编译时代码,我认为它并没有渐近不同,因为在编译时,无论如何,您都需要为任何循环计算的每次迭代实例化一个新类型/函数/某些东西。在这里,无论如何你都在输出那个大小的结构。
标签: c++ templates c++11 metaprogramming template-meta-programming