【问题标题】:C++, template or pointer to member functionC++、模板或指向成员函数的指针
【发布时间】:2015-05-26 00:58:23
【问题描述】:

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

这是我的一个函数的示例:

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(..)
  • try...catch 块中调用的成员函数(属于md 类)

基本上我想避免在我的每个CalController::XXX_cmd(...) 函数中重复try..catch 块和LOG(..) 消息。

使用boost::function 和或boost::bind 就可以了,我只是在兜圈子,不知道如何设置它。

【问题讨论】:

    标签: c++ templates boost member-functions


    【解决方案1】:

    您可以编写一个成员函数来完成所有这些工作。不需要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);
    }
    

    【讨论】:

    • 哇哦,这就是我的目标。谢谢!函数指针的语法仍然有点挣扎,但它开始变得更有意义了。
    • @tbc fn 在我的示例中不完全是函数指针,它是指向成员函数的指针。完全不同的生物。必须使用奇怪的 (md-&gt;*fn)() 语法使用实例调用它。
    • 啊,好的,感谢您的澄清。显然仍在挣扎:-)。
    【解决方案2】:

    我认为你可以通过一个简单的常规函数​​得到你想要的。不需要模板:

    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++ 了,甚至更长时间没有做任何增强的东西了,所以虽然我认为上面的总体思路是正确的,但如果它真的编译了,我会感到惊讶。

    【讨论】:

    • 谢谢,这很有帮助,但我同意你的观点,尤其是。 #2。我将接受 Barry 的回答,因为它更符合我的需要。
    【解决方案3】:

    如果使用 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,按照类型签名创建普通函数并将它们作为参数传递,或者传递成员函数指针 - 您可以看看巴里的答案。

    【讨论】:

    • 谢谢!我的项目还不能使用 C++11,但很高兴看看事情是如何工作的。
    猜你喜欢
    • 1970-01-01
    • 2011-12-09
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 2012-07-05
    • 2023-03-28
    相关资源
    最近更新 更多