better than enum



我有很多数据,在循环中我需要放置一个选择。每次进入都是一个物理事件。在每一个事件中,只有一个粒子具有它的性质:

for (...)   {  // loop over entries in the data
    if (not selection()) continue;
    ...
}

从命令行中选择要考虑的特定粒子类型,例如:

Options options = get_options(argc, argv);
enum ParticleType_type {ELE, PHO, ...}
cout << "particle: " << get_particle_name(options.particle_type);
for (entry in data) { // loop over data
    // read variale like PDG, conv, ... for the entry
    switch (options.particle_type)
    {
          case ELE: if (PDG != 11) continue; break;
          case PHO: if (PDG != 22) continue; break;
          case PHO_UNC:   if (PDG != 22 or conv) continue; break;
          case PHO_CONV:  if (PDG != 22 or !conv) continue; break;
          case PHO_1TRK:  if (PDG != 22 or !conv or !is1trak) continue; break;
          case PHO_2TRK:  if (PDG != 22 or !conv or !is2trak) continue; break;
          case PHOR1:     if (PDG != 22 or !conv or !(r>0 and <=200) continue; break;
          case PHOR2:     if (PDG != 22 or !conv or !(r>200 and <=400) continue; break;
          case PHOR3:     if (PDG != 22 or !conv or !(r>400 and <=600) continue; break;
          case PHOR4:     if (PDG != 22 or !conv or !(r>600 and <=800) continue; break;
    }
    do_something();
    if (isPhoton(options.particle_type)) // true for every PHO_XXX
    {
         if (options.particle_type in [PHORX])
         {
              int rbin = get_Rbin(options.particle_type) // PHOR1 -> 1, PHOR2 -> 2
              ...
         }  
         ...
    }
}
cout << "output: " << get_file_name(options.particle_type) + ".out";

如你所见:

  1. 不是一团糟
  2. 有子类别,例如PHO_CONVPHO, PHO_1TRKPHO_CONV
  3. 每个ParticleType_type都有一些属性,如名称,file_name和更多
  4. 现在我需要使用r步长为100而不是200将PHORx的类别加倍。我想以某种方式参数化范围,可能使用模板参数
  5. 我需要跨类别例如创建PHOR1_1TRK
  6. (不太相关)我由I/O主导。目前,如果我想处理PHOELE,我需要运行两次,我想同时做它们

我认为最好的解决方案是为每个ParticleType_type创建一个类,并将get_file_name等函数作为成员函数。问题是类不是对象,所以我不能将它们作为函数的参数传递:例如,现在我可以用enum编写自由函数,将ParType_type作为参数,但对于类,我不能。

我想自动创建参数类型,例如PHORX。

谁能建议一些技巧?

Flyweight模式在这里可能对您有用。

不再为每个粒子提供一个带有其类型枚举的实例,而是为每个粒子提供一个单独的实例,并为该类型的每个粒子提供一个指向该实例的指针。粒子类型将接受一个指向你的粒子结构体的指针来进行计算。

// pseudocode!
ParticleA a;
ParticleB b;
struct ParticleData {
  Particle * type;
  int data;
} particles[] = {
  { &a, 5 },
  { &a, 7 },
  { &b, 4 },
 // ... 
};
for each( particle in particles ) {
  particle->type->do_something(particle);
}

为每种粒子类型创建类(可能是抽象的粒子类的子类)看起来是正确的方法。

你不会传递一个类给一个函数,你会传递一个实例

你可以使用表格驱动的方法,而不是为所有的粒子编写单独的类。

你可以创建一个表,使用ParticleType_type作为索引来获取一个函数指针,或者使用boost::function来进行特定于粒子的处理。

最新更新