簡體   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