C++ 如何将3个嵌套循环重写为单个循环?

C++ 如何将3个嵌套循环重写为单个循环?,c++,for-loop,parallel-processing,openmp,C++,For Loop,Parallel Processing,Openmp,我有这个结构: struct Wrapper { public: const int r_range; const int c_range; ... } 那么我有这个代码: vector<Wrapper> wrappers; //fill wrappers somehow const int wrappersSize = wrappers.size(); for(size_t i=0; i < wrappersSize; i++) for(int r=0

我有这个结构:

struct Wrapper {
  public:
  const int r_range;
  const int c_range;
  ...
}
那么我有这个代码:

vector<Wrapper> wrappers;
//fill wrappers somehow
const int wrappersSize = wrappers.size();
for(size_t i=0; i < wrappersSize; i++)
  for(int r=0 ; r < wrappers[i].r_range; r++)
    for(int c=0; c < wrappers[i].c_range; c++)
      foo(wrappers[i], r, c);

当然,使用
reserve
和避免
push_-back
可以更有效地做到这一点,但我想知道是否有更简单/更有效/更优雅/任何解决方案。

隐藏“丑陋”的最简单方法是在这样一个函数中,将

#include <vector>

struct WrapperIndex {
    const Wrapper& wrapper;
    const int r;
    const int c;
};

template<typename T>
auto make_wrapper_index_container(const T& wrappers) {
    std::vector<WrapperIndex> indices;
    for (const auto& wrapper : wrappers) {
        for (int r = 0; r < wrapper.r_range; r++) {
            for (int c = 0; c < wrapper.c_range; c++) {
                indices.emplace_back(WrapperIndex{wrapper, r, c});
            }
        }
    }
    return indices;
}

...

auto index_container = make_wrapper_index_container(wrappers);
#pragma omp parallel for
for (auto it = index_container.begin(); it < index_container.end(); ++it) {
    foo(it->wrapper, it->r, it->c);
}
#包括
结构包装器索引{
常量包装器&包装器;
常数INTR;
const int c;
};
模板
自动生成包装器索引容器(常量和包装器){
std::向量指数;
用于(常量自动和包装器:包装器){
对于(int r=0;rwrapper,it->r,it->c);
}

动态确定
r
r
将需要对
wrappers
中的不同条目进行多次查找,这对性能非常不利(非常量索引确定)。因此,在这里使用一些额外的内存是正确的做法。

隐藏“丑陋”的最简单方法是将
struct
s的单个
std::vector
设置为如下函数:

#include <vector>

struct WrapperIndex {
    const Wrapper& wrapper;
    const int r;
    const int c;
};

template<typename T>
auto make_wrapper_index_container(const T& wrappers) {
    std::vector<WrapperIndex> indices;
    for (const auto& wrapper : wrappers) {
        for (int r = 0; r < wrapper.r_range; r++) {
            for (int c = 0; c < wrapper.c_range; c++) {
                indices.emplace_back(WrapperIndex{wrapper, r, c});
            }
        }
    }
    return indices;
}

...

auto index_container = make_wrapper_index_container(wrappers);
#pragma omp parallel for
for (auto it = index_container.begin(); it < index_container.end(); ++it) {
    foo(it->wrapper, it->r, it->c);
}
#包括
结构包装器索引{
常量包装器&包装器;
常数INTR;
const int c;
};
模板
自动生成包装器索引容器(常量和包装器){
std::向量指数;
用于(常量自动和包装器:包装器){
对于(int r=0;rwrapper,it->r,it->c);
}


动态确定
r
r
将需要对
wrappers
中的不同条目进行多次查找,这对性能非常不利(非常量索引确定)。因此,在这里使用一些额外的内存是正确的做法。

afaik将最外层的循环并行化无论如何都会更好,因此我认为没有必要在您的计算机上更改某些内容loops@tobi303你说得对,但我们不是在并行内部循环,而是在折叠它们,这在负载严重不平衡的情况下特别方便,就是这个案子!你的代码和我的差不多。它可能不是特别优雅,但我也不认为它可怕。有时你不得不为表现而受苦。。。我会使用
std::tuple
struct
作为三个索引。如果你非常喜欢它,你可以在随机访问迭代器中隐藏所有内容(OpenMP确实支持它们)。@justHelloWorld在CodeReview上重新发布也可以。请注意,CR需要实际的、未更改的代码。最好直接从IDE开始。在其“当前形式”中,它有可能作为伪代码/示例代码关闭。。。不要担心评论。无论如何,评论可以在任何时候被删除,并不意味着要在Verafaik中持久化。无论如何,最好是将最外层的循环并行化,所以我看不出有任何需要在您的loops@tobi303你是对的,但我们不是在并行内部循环,而是在折叠它们,这在负载不平衡严重的情况下特别方便,就是这种情况!你的代码和我的差不多。它可能不是特别优雅,但我也不认为它可怕。有时你不得不为表现而受苦。。。我会使用
std::tuple
struct
作为三个索引。如果你非常喜欢它,你可以在随机访问迭代器中隐藏所有内容(OpenMP确实支持它们)。@justHelloWorld在CodeReview上重新发布也可以。请注意,CR需要实际的、未更改的代码。最好直接从IDE开始。在其“当前形式”中,它有可能作为伪代码/示例代码关闭。。。不要担心评论。无论如何,注释可以在任何时候被删除,并且不意味着永久保留。如果我不想对
包装器
使用
const
,该怎么办?上面的代码给了我错误,因为
emplace\u back
(我不熟悉,据我理解,在这种情况下应该更有效)如果需要,可以省略
const
,但是你必须非常小心比赛条件
emplace\u back
在这里并不重要,因为由于缺少构造函数,我构建了一个临时的
WrapperIndex
。检查是否有进一步的改进。这段代码符合C++14。我已经测试过这个解决方案。首先,我注意到了一个改进,它是在
WrapperIndex
const int I
中保存的,而不是
Wrapper&Wrapper
,特别是因为我为每个
I
保存了一些其他东西,所以只保存
I
更便宜、更快。但是,即使使用
reserve()
,填充
索引也需要18毫秒(使用英特尔编译器和opitmizionation标志),这对我的应用程序来说是相当多的。太遗憾了。@justHelloWorld我的代码是用于示例
foo
函数的。如果您直接使用
i
,那么这样做当然是有意义的。通过使用某种范围树,您可能可以节省一些设置时间。但这将花费您对数访问时间。如果平均而言,
c_范围
s足够大,那么从理论上讲,实时计算指数可能是有益的。然而,这确实假设您的