![](/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.