将对象范围扩展到if语句之外

时间:2015-07-11 00:26:16

标签: c++ template-meta-programming

我有以下C ++设计问题。

假设我有以下课程:

class Model {
  Model(int numberOfModels, int flag=-1) : 
    _models(numberOfModels), _flag(flag){ }

  void buildModel(){
    for (int id=0; id<_models.size(); ++id) {
      if (flag == -1){
        BuilderOne builder;
        builder.build(&_models[id]);
      }
      else {
        BuilderTwo builder;
        builder.build(&_models[id]);
      }
    }
  } 

  private:
    vector<SimpleModel> _models;
    int _flag;
};

其中成员函数“buildModel”构建“SimpleModel”对象的向量。 “BuilderOne”和“BuilderTwo”是不同的构建器类,它们都实现了“构建”方法(或者它们可以使用CRTP从相同的BaseBuilder类继承)。

但是上面的实现非常麻烦,因为构造器的类型应该在进入循环之前由“_flag”预先确定。我真正想要的是“buildModel”方法的以下实现:

void buildModel(){
  if (flag == -1){
    BuilderOne builder;
  else
    BuilderTwo builder;

  for (int id=0; id<_models.size(); ++id)
    builder.build(&_models[id]);       
} 

但是,上面的代码没有编译,因为1)在if语句之后对象“builder”不可见2)在编译时无法确定“builder”的类型。

通过在BaseBuilder中将“构建”方法设为虚函数,可以轻松实现上述功能。但由于我们库中的各种原因,实际上功能不被视为解决方案。但继承(如CRTP)是可以接受的。

有人可以帮忙解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

使用[insane] 要求无法使用虚拟功能时,您当前的实现就会被破坏。每次添加新的构建器类型时,您都必须更新Model类。这可能正是你想要的(你的帖子不清楚),所以我试着用一个解决方案来覆盖这两种方法。

首先,您可以从利用静态多态性开始,并将主要功能放在函数模板中。这将帮助您避免缺少虚函数来减少使用它所需的代码量。

class Model
{
public:
    template<class BuilderType>
    BuilderType buildModel()
    {
        BuilderType builder;

        //  Perform other tasks here

        for (int id = 0; id<_models.size(); ++id)
        {
            builder.build(&_models[id]);
        }

        //  Perform other tasks here

        return builder;
    }
};

这将允许您使用对象类型,只要它实现一个build函数,该函数获取指向SimpleModel实例的指针。您还可以选择将构建器作为函数的参数,以允许自动类型推导。无论您是公开的,私人的还是受保护的,都取决于您以及您决定如何向前发展。这可能是您需要的全部内容,但如果您想将buildModel功能限制为特定的一组构建器,则可以将其设置为受保护或私有,并提供简化构建过程的公共功能。

class Model
{
public:
    void buildModel()
    {
        switch (flag_)
        {
        case -1:
            buildModelByType<BuilderOne>(b);
            break;

        default:
            buildModelByType<BuilderTwo>(b);
            break;
        }
    }

protected:

    template<class BuilderType>
    BuilderType buildModelByType()
    {
        BuilderType builder;

        //  Perform other tasks here

        for (int id = 0; id<_models.size(); ++id)
        {
            builder.build(&_models[id]);
        }

        //  Perform other tasks here

        return builder;
    }
};

您是通过参数获取构建器还是返回构建过程的结果取决于您。你的帖子并没有具体说明问题的这一方面,但这应该很容易适应你所处的任何方面。