C ++,模板或指向成员函数的指针

时间:2015-05-26 00:58:23

标签: c++ templates boost member-functions

我有一系列非常相似的成员函数,我想我可以通过模板或其他方法使代码更易于维护,但我不知道该怎么做。

以下是我的一个功能示例:

void CalController::bgc_cmd(const std::string& s) {
  try {
    this->cohort_ptr->md->set_bgcmodule(temutil::onoffstr2bool(s));

    LOG(note) << "CalController turned bgc module to " 
              << s <<" via cohort pointer...";

  } catch (const std::runtime_error& e) {
    LOG(warn) << e.what();
  }
}

我的其他功能完全相同,除了:

  • 函数名称(即bgc_cmd(..)env_cmd(..)dsl_cmd(..)
  • md块中调用的try...catch类的成员函数

基本上,我希望避免在每个try..catch函数中复制LOG(..)阻止和CalController::XXX_cmd(...)消息。

使用boost::function和/或boost::bind会很好,我只是围成一圈,无法弄清楚如何设置它。

3 个答案:

答案 0 :(得分:2)

你可以写一个成员函数来做所有这些事情。没有必要bind或模板,因为md上的所有内容都是一个采用相同参数类型的函数。我将使用MD作为md的类型,我假设onoffstr2bool返回bool

void set_cmd(void (MD::*fn)(bool), const std::string& name, const std::string& s)
{
  try {
    (this->cohort_ptr->md->*fn)(temutil::onoffstr2bool(s));

    LOG(note) << "CalController turned " << name << " to " 
              << s <<" via cohort pointer...";

  } catch (const std::runtime_error& e) {
    LOG(warn) << e.what();
  }
}

然后你会称之为:

void CalController::bgc_cmd(const std::string& s) {
    set_cmd(&MD::set_bgcmodule, "bgc module", s);
}

答案 1 :(得分:1)

我认为你可以通过一个简单的常规功能得到你想要的东西。无需模板:

void CalController::do_cmd(boost::function<void (String)> fun, const std::string& s) {
  try {
    fun(temutil::onoffstr2bool(s));

    LOG(note) << "CalController turned bgc module to " 
              << s <<" via cohort pointer...";

  } catch (const std::runtime_error& e) {
    LOG(warn) << e.what();
  }
}

然后你可以使你的其他方法类似:

void CalController::bgc_cmd(const std::string& s) {
    // here TypeOfMd is whatever the type is for this->cohort_ptr->md.
    // This binds the "this pointer" for set_bgcmodule to this->cohort_ptr->md
    do_cmd(boost::bind(&TypeOfMd::set_bgcmodule, this->chort_prt->md), s);
}

这里需要注意的一些事项:

  1. 使用C ++ 11 lambdas和新功能类提升是不必要的
  2. 我认为上述方法有效,但我不确定保存几行代码是否值得额外的复杂性和可读性的损失。它可能也很难维护,因为您希望对每种方法稍作不同的日志消息进行微小的更改。
  3. 自从我写了任何C ++之后已经有一段时间了,因为我做了任何提升的事情,所以当我认为上面是正确的一般想法时,如果它真的编译了,我会感到惊讶。 / LI>

答案 2 :(得分:1)

如果使用C ++ 11,您可以使用更通用的名称创建一个函数,让我们说exex_cmd。 然后,您可以将lambda函数作为参数传递,并在try / catch块中执行它 - 无需使用模板。

//WARNING: Untested code - the point is that you get the idea. Modify at will.
void CalController::exec_cmd(const std::function<void (void)> func) {
  try {
    //Invoke lambda.
    //The string is passed via closure implementation,
    //but you can always pass it as normal argument if you want.
    func();

    LOG(note) << "CalController turned bgc module to " 
              << s <<" via cohort pointer...";

  } catch (const std::runtime_error& e) {
    LOG(warn) << e.what();
  }
}

然后,创建3个包装器方法,调用exec_cmd,但传递一个不同的lambda作为参数:

  void CalcController::bgc_cmd(const std::string& s){
    CalcController::exec_cmd([=] () {
      //Taking closures into control, to avoid passing the string as argument.
      this->cohort_ptr->md->set_bgcmodule(temutil::onoffstr2bool(s));
    })
  }

  void CalcController::env_cmd(const std::string& s){
    CalcController::exec_cmd([=] () {
       //different function invocation here.
    })
  }

同样,你可以为你的所有功能做到这一点。

您可以查看here了解有关C ++ 11的lambda的更多信息。

普通C ++中的类似方法是定义函数指针类型并将函数指针传递给exec_cmd,在类型签名后创建正常函数并将它们作为参数传递,或传递成员函数指针 - 你可以看看巴里的答案。