繁体   English   中英

如何分解嵌套的 for 循环?

[英]How do I factor out nested for loops?

很多时候,我需要对一组 class 数据进行批量操作。 考虑这些类:

#include <vector>


class Component {
public:
    bool isFixed;
    int a, b, c;

    Component():
    isFixed(false),
    a(0), b(0), c(0)
    {}
};


class System {
public:
    std::vector<Component> components;

    System(int numComponents):
    components(numComponents)
    {}
};


class Universe {
public:
    std::vector<System> systems;

    Universe(int numSystems, int numComponents):
    systems(numSystems, System(numComponents))
    {}
};

现在,对Universe中的每个Component执行单个操作就变成了遍历Universe中所有System的所有Component的问题:嵌套for循环。

// Fixes a Component.
//
void fixComponent(Component& c) {c.isFixed = true;}


// Adds a number to the pieces of a Component.
//
void addToComponent(Component& cmp, double k)
{
    cmp.a += k;
    cmp.b += k;
    cmp.c += k;
}


// Fixes all components in a Universe.
//
void fixAllComponents(Universe& universe)
{
    for(std::size_t i = 0; i < universe.systems.size(); ++i) {

        System& thisSystem = universe.systems.at(i);

        for(std::size_t j = 0; j < thisSystem.components.size(); ++j) {
            fixComponent(thisSystem.components.at(j));
        }
    }
}


// Adds a number to all components in a Universe.
//
void addToAllComponents(Universe& universe, double k)
{
    for(std::size_t i = 0; i < universe.systems.size(); ++i) {

        System& thisSystem = universe.systems.at(i);

        for(std::size_t j = 0; j < thisSystem.components.size(); ++j) {
            addToComponent(thisSystem.components.at(j), k);
        }
    }
}

编写两次迭代for循环是可以的,但我可以轻松地对这些数据执行 20 个不同的任务for每次都必须重写双精度。 不用说,这很容易出错。 如果我能以某种方式重用迭代代码并只关注不同的单个任务,那就太好了。

问题是否有一种标准方法可以在迭代集合时“分解” for循环?

尝试经过一番思考,我决定编写一个 function,它采用 2 个参数,包含要迭代的数据的 object 和一个指向执行任务的 function 的指针。

void forEachComponent(Universe& u, void (*task)(Component&))
{
    for(std::size_t i = 0; i < u.systems.size(); ++i) {

        System& thisSystem = u.systems.at(i);

        for(std::size_t j = 0; j < thisSystem.components.size(); ++j) {
            task(thisSystem.components.at(j));
        }
    }
}

现在,如果我想修复一个组件,我可以简单地调用forEachComponent()并传入要执行的任务。

Universe theUniverse(20, 30);
forEachComponent(theUniverse, fixComponent);

这个“解决方案”的明显问题是,对于每个涉及不同参数的任务,例如addToComponent() ,我必须编写另一个 function ,它需要一个指向具有这些参数的 function 的指针,这违背了分解for循环的目的。

您可以使用仿函数重用用于迭代组件的逻辑。

template <typename Functor >
void forEachComponent(Universe& universe, Functor functor)
{
    for(std::size_t i = 0; i < universe.systems.size(); ++i) {

        System& thisSystem = universe.systems.at(i);

        for(std::size_t j = 0; j < thisSystem.components.size(); ++j) {
            functor(thisSystem.components.at(j));
        }
    }
}

// Fixes all components in a Universe.
void fixAllComponents(Universe& universe)
{
   forEachComponent(universe, [](Component& c) {fixComponent(c);});
}


// Adds a number to all components in a Universe.
void addToAllComponents(Universe& universe, double k)
{
   forEachComponent(universe, [k](Component& c) {addToComponent(c, k);});
}

您可以通过使用 range- for循环来简化forEachComponent

template <typename Functor >
void forEachComponent(Universe& universe, Functor functor)
{
    for(System& system : universe.systems) {
        for(Component& c : system.components) {
            functor(c);
        }
    }
}

执行此操作的 OOP 方法是定义抽象 class:

class Task {
    void execute(Component &) = 0;
}

现在您可以将forEachComponent()定义为

void forEachComponent(Universe& u, Task& task)

并在 for 循环中调用task.execute()

或者,您可以将forEachComponet()定义为模板:

template <class Task>
void forEachComponent(Universe& u, Task& task)

现在传递给这个 function 的任何东西都必须覆盖operator()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM