RAC*_*RAC 23 c++ optimization templates metaprogramming
我在下面有一个带有运行时for循环的C++代码段,
for(int i = 0; i < I; i++)
for (int j = 0; j < J; j++)
A( row(i,j), column(i,j) ) = f(i,j);
Run Code Online (Sandbox Code Playgroud)
该片段被重复调用.循环边界'I'和'J'在编译时是已知的(I/J是2到10的顺序).我想以某种方式使用模板展开循环.主要的瓶颈是row()和column()以及f()函数.我想用使用row<i,j>::enum技巧在编译时评估的等效元程序替换它们.
我真正喜欢的是最终将循环解析为一系列语句的东西,例如:
A(12,37) = 0.5;
A(15,23) = 0.25;
A(14,45) = 0.25;
Run Code Online (Sandbox Code Playgroud)
但是我想这样做而不会破坏for- for结构太多.本着精神:
TEMPLATE_FOR<i,0,I>
TEMPLATE_FOR<j,0,J>
A( row<i,j>::value, column<i,j>::value ) = f<i,j>::value
Run Code Online (Sandbox Code Playgroud)
可以提升:: lambda(或其他东西)帮我创建吗?
T.E*_*.D. 12
一个好的编译器应该为你展开.例如,在gcc中使用-O2选项进行编译会打开循环展开.
如果您尝试自己手动完成,除非您仔细测量并真正知道自己在做什么,否则最终会导致代码变慢.例如,在您手动展开的情况下,您可能会阻止编译器进行循环交换或stripmine优化(在gcc文档中查找--floop-interchange和-floop-strip-mine )
这是直接执行此操作的方法:
template <int i, int j>
struct inner
{
static void value()
{
A(row<i,j>::value, column<i,j>::value) = f<i,j>::value;
inner<i, j+1>::value();
}
};
template <int i> struct inner<i, J> { static void value() {} };
template <int i>
struct outer
{
static void value()
{
inner<i, 0>::value();
outer<i+1>::value();
}
};
template <> struct outer<I> { static void value() {} };
void test()
{
outer<0>::value();
}
Run Code Online (Sandbox Code Playgroud)
如有必要,您可以A作为参数传递给每个values.
这是一种使用可变参数模板的方法,不需要硬编码的I和J:
#include <utility>
template <int j, class Columns>
struct Inner;
template <class Columns, class Rows>
struct Outer;
template <int j, int... i>
struct Inner<j, std::index_sequence<i...>>
{
static void value() { (A(column<i, j>::value, row<i, j>::value), ...); }
};
template <int... j, class Columns>
struct Outer<std::index_sequence<j...>, Columns>
{
static void value() { (Inner<j, Columns>::value(), ...); }
};
template <int I, int J>
void expand()
{
Outer<std::make_index_sequence<I>, std::make_index_sequence<J>>::value();
}
void test()
{
expand<3, 5>();
}
Run Code Online (Sandbox Code Playgroud)
(生成程序集的代码段:https://godbolt.org/g/DlgmEl)
你可以使用Boost MPL.
循环展开的一个例子是在这个mpl :: for_each页面上.
for_each< range_c<int,0,10> >( value_printer() );
Run Code Online (Sandbox Code Playgroud)
它似乎并没有在编译时进行全部评估,但它可能是一个很好的起点.