您可以使用 std::function。像这样的:
// define a type for the function
typedef std::function< void(particle const&, float *fxfyfz) > forcer_function;
std::vector< forcer_function > forces;
现在,关于性能的一些话。由于这是您正在谈论的粒子,因此我假设您有相当多的粒子(例如,至少有数百个)。所以我假设你有兴趣让这段代码以适度的速度运行。
因此,首先,由于缓存属性不好,不建议对容器使用 std::list。它会使你的代码大大变慢。因此,使用std::vector。
其次,将力列表添加为粒子结构的成员并不常见。你真的想对每个粒子使用不同的力吗?通常,有 100-1000 个粒子。如果您可以对所有粒子使用相同的力集合,那么将力移出粒子类将为您带来好处。例如,
struct particle
{
double mass;
// position
double x, y, z;
// velocity
double dx, dy, dz;
};
struct particle_container
{
std::vector< particle > particles;
std::vector< forcer_function > forces;
void update();
};
void particle_container::update()
{
for(particle &p : particles) {
double rx, ry, rz;
rx = ry = rz = 0.0;
for(forcer_function fn : forces) {
double f[3];
fn(p, &f[0]);
rx += f[0];
ry += f[1];
rz += f[2];
}
// integrate resulting force, etc
// ...
}
}
如果 OTOH 你真的想使用每粒子力,你仍然可以使用我上面概述的方法,将具有相同力集合的粒子分组到不同的容器对象中。然后你可以重用以上所有内容,再添加一个类将修复它:
struct particle_groups
{
std::vector< particle_container > groups;
void update();
};
void particle_groups::update()
{
for(auto &g : groups) {
g.update();
}
};
如果你真的真的不想分组,那么至少考虑一下是否有一种方法可以使用粒子成员将非活动力归零。然后你仍然可以使用上面的方法。例如,像这样:
struct particle
{
double mass;
// position
double x, y, z;
// velocity
double dx, dy, dz;
// is gravity active? either 1.0 or 0.0
double grav;
// is player interaction active? either 1.0 or 0.0
double player;
// etc... for all possible forces
};
然后只需将产生的重力乘以粒子的重力成员,然后根据particle.grav 的值是 1.0 还是 0.0,有效地关闭或打开该粒子的重力。
最后,std::function 很慢。您可以混合使用上述两种方法并使用单个函数。像这样:
struct particle
{
double mass;
// position
double x, y, z;
// velocity
double dx, dy, dz;
};
struct force_settings
{
double grav;
double attractor;
double player;
//etc...
};
struct particle_container
{
// no need to keep pointers to functions
force_settings forces;
std::vector< particle > particles;
void update();
void compute_forces(particle const& p, double *rf) const
{
// zero resulting force
rf[0] = rf[1] = rf[2] = 0.0;
// compute gravity, (assume y axis)
rf[1] += forces.grav * 9.8; // will be either 9.8 or 0.0
// compute attractor
double ax = p.x - attractor.x;
double ay = p.y - attractor.y;
double az = p.z - attractor.z;
rf[0] += forces.attraction * ax*ax;
rf[1] += forces.attraction * ay*ay;
rf[2] += forces.attraction * az*az;
// etc... more forces here
}
};
void particle_container::update()
{
for(particle &p : particles) {
double rf[3];
compute_forces(p, &rf);
// integrate, etc...
}
}