![](/img/trans.png)
[英]How do I specify the specific the control points in a De Casteljau algorithm, if I am using nested for loops to iterate?
[英]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.