[英]How do I factor out nested for loops?
Often times, I need to do bulk operations on a set of class data.很多时候,我需要对一组 class 数据进行批量操作。 Consider these classes:
考虑这些类:
#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))
{}
};
Now, doing a single operation to every Component
in a Universe
becomes a matter of looping through all the Component
s of all the System
s in a Universe
: a nested for
loop.现在,对
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);
}
}
}
Writing the iterative for
loops twice is OK, but I could easily have 20 different task to perform on this data, having to rewrite the double for
every time.编写两次迭代
for
循环是可以的,但我可以轻松地对这些数据执行 20 个不同的任务for
每次都必须重写双精度。 Needless to say, this can be error-prone.不用说,这很容易出错。 It would be nice if I could somehow reuse the iterating code and just focus on the distinct individual tasks.
如果我能以某种方式重用迭代代码并只关注不同的单个任务,那就太好了。
Question Is there a standard way to "factor out" the for
loops when iterating over a set?问题是否有一种标准方法可以在迭代集合时“分解”
for
循环?
Attempt After some thinking, I decided to write a function that takes 2 parameters, the object containing the data to iterate over and a pointer to a function that performs the task.尝试经过一番思考,我决定编写一个 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));
}
}
}
Now, if I want to fix a component, I can simply call forEachComponent()
and pass in the task to be performed.现在,如果我想修复一个组件,我可以简单地调用
forEachComponent()
并传入要执行的任务。
Universe theUniverse(20, 30);
forEachComponent(theUniverse, fixComponent);
The obvious problem with this "solution" is that for every task that involves different parameters like addToComponent()
, I have to write another function that takes a pointer to a function with those parameters, which defeats the purpose of factoring out the for
loops.这个“解决方案”的明显问题是,对于每个涉及不同参数的任务,例如
addToComponent()
,我必须编写另一个 function ,它需要一个指向具有这些参数的 function 的指针,这违背了分解for
循环的目的。
You can reuse the logic for iterating over the components by using functors.您可以使用仿函数重用用于迭代组件的逻辑。
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);});
}
You can simplify forEachComponent
by using range- for
loops.您可以通过使用 range-
for
循环来简化forEachComponent
。
template <typename Functor >
void forEachComponent(Universe& universe, Functor functor)
{
for(System& system : universe.systems) {
for(Component& c : system.components) {
functor(c);
}
}
}
An OOP way to do this is define an abstract class:执行此操作的 OOP 方法是定义抽象 class:
class Task {
void execute(Component &) = 0;
}
Now you can define forEachComponent()
as现在您可以将
forEachComponent()
定义为
void forEachComponent(Universe& u, Task& task)
and call task.execute()
in the for loop.并在 for 循环中调用
task.execute()
。
Alternatively, you can define forEachComponet()
as a template:或者,您可以将
forEachComponet()
定义为模板:
template <class Task>
void forEachComponent(Universe& u, Task& task)
And now anything passed into this function must override operator()
.现在传递给这个 function 的任何东西都必须覆盖
operator()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.