说我有一个像窝一样的循环
for (int x = xstart; x < xend; x++){
for (int y = ystart; y < yend; y++){
for (int z = zstart; z < zend; z++){
function_doing_stuff(std::make_tuple(x, y, z));
}
}
}
Run Code Online (Sandbox Code Playgroud)
并希望将其转化为
MyRange range(xstart,xend,ystart,yend, zstart,zend);
for (auto point : range){
function_doing_stuff(point);
}
Run Code Online (Sandbox Code Playgroud)
我如何编写MyRange类与嵌套for循环一样高效?这样做的动机是能够使用std算法(例如转换,累积等),并创建主要与维度无关的代码.
通过使用迭代器,可以轻松创建在1d,2d或3d点范围内运行的模板化函数.
代码库目前是C++ 14.
编辑:
写清楚的问题很难.我会试着澄清一下.我的问题不是写一个迭代器,我能做到.相反,问题是性能问题:是否有可能使迭代器与嵌套for循环一样快?
使用range/v3,您可以这样做
auto xs = ranges::view::iota(xstart, xend);
auto ys = ranges::view::iota(ystart, yend);
auto zs = ranges::view::iota(zstart, zend);
for (const auto& point : ranges::view::cartesian_product(xs, ys, zs)){
function_doing_stuff(point);
}
Run Code Online (Sandbox Code Playgroud)
您可以将自己的课程介绍为
class myClass {
public:
myClass (int x, int y, int z):m_x(x) , m_y(y), m_z(z){};
private:
int m_x, m_y, m_z;
}
Run Code Online (Sandbox Code Playgroud)
然后std::vector<myClass>用你的三重循环初始化a
std::vector<myClass> myVec;
myVec.reserve((xend-xstart)*(yend-ystart)*(zend-zstart)); // alloc memory only once;
for (int x = ystart; x < xend; x++){
for (int y = xstart; y < yend; y++){ // I assume you have a copy paste error here
for (int z = zstart; z < zend; z++){
myVec.push_back({x,y,z})
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后,你可以使用所有漂亮的std算法std::vector<myClass> myVec.用语法糖
using MyRange = std::vector<MyClass>;
Run Code Online (Sandbox Code Playgroud)
和
MyRange makeMyRange(int xstart, int xend, int ystart, int yend, int zstart,int zend) {
MyRange myVec;
// loop from above
return MyRange;
}
Run Code Online (Sandbox Code Playgroud)
你可以写
const MyRange range = makeMyRange(xstart, xend, ystart, yend, zstart, zend);
for (auto point : range){
function_doing_stuff(point);
}
Run Code Online (Sandbox Code Playgroud)
使用新的移动语义,这不会创建不需要的副本.请注意,此功能的界面相当糟糕.也许宁愿使用3对int,表示x,y,z间隔.
也许您将名称更改为有意义的名称(例如,myClass可能是Point).
另一个直接移植任何循环代码的选项是使用Coroutine.这是yield从Python或C#模拟的.
using point = std::tuple<int, int, int>;
using coro = boost::coroutines::asymmetric_coroutine<point>;
coro::pull_type points(
[&](coro::push_type& yield){
for (int x = xstart; x < xend; x++){
for (int y = ystart; y < yend; y++){
for (int z = zstart; z < zend; z++){
yield(std::make_tuple(x, y, z));
}
}
}
});
for(auto p : points)
function_doing_stuff(p);
Run Code Online (Sandbox Code Playgroud)
由于您关心性能,因此在可预见的将来您应该忘记组合迭代器。核心问题是编译器还无法理清混乱并找出其中有 3 个自变量,更不用说执行任何循环交换或展开或融合。
如果必须使用范围,请使用编译器可以识别的简单范围:
for (int const x : boost::irange<int>(xstart,xend))
for (int const y : boost::irange<int>(ystart,yend))
for (int const z : boost::irange<int>(zstart,zend))
function_doing_stuff(x, y, z);
Run Code Online (Sandbox Code Playgroud)
或者,您实际上可以将函子和提升范围传递给模板:
template <typename Func, typename Range0, typename Range1, typename Range2>
void apply_ranges (Func func, Range0 r0, Range1 r1, Range2 r2)
{
for (auto const i0 : r0)
for (auto const i1 : r1)
for (auto const i2 : r2)
func (i0, i1, i2);
}
Run Code Online (Sandbox Code Playgroud)
如果您真正关心性能,那么您不应该使用复杂的范围来扭曲您的代码,因为当您想在 AVX 内在函数中重写它们时,它们会让您更难理清它们。
| 归档时间: |
|
| 查看次数: |
549 次 |
| 最近记录: |