将另一个类的成员函数传递给std :: function参数

时间:2018-08-29 08:41:03

标签: c++ class c++11 function-pointers std-function

我有一个带有函数的类,该函数带有一个std::function并将其存储。这部分似乎可以编译(但请指出是否存在任何问题)

#include <functional>
#include <iostream>

struct worker
{
   std::function<bool(std::string)> m_callback;
   void do_work(std::function<bool(std::string)> callback)
   {
      m_callback = std::bind(callback, std::placeholders::_1);
      callback("hello world\n");
   }
};

// pretty boring class - a cut down of my actual class
struct helper
{
   worker the_worker;
   bool work_callback(std::string str)
   {
      std::cout << str << std::endl;
      return true;
   }
};

int main()
{
   helper the_helper;
   //the_helper.the_worker.do_work(std::bind(&helper::work_callback, the_helper, std::placeholders::_1));  // <---- SEGFAULT (but works in minimal example)
   the_helper.the_worker.do_work(std::bind(&helper::work_callback, &the_helper, std::placeholders::_1));  // <---- SEEMS TO WORK
}

我得到一个 segfault ,但是我不确定为什么。实际上,我之前曾使用过此示例,实际上是从另一个使用过的地方复制了此示例。成员函数是我从中调用的类的一部分(即this而不是the_helper)的唯一真正区别。

所以这就是为什么我还要问我是否总体上还做错了什么?我应该将std::function传递为:

void do_work(std::function<bool(std::string)>&& callback)

void do_work(std::function<bool(std::string)>& callback)

3 个答案:

答案 0 :(得分:1)

@ Rakete1111在评论中也指出,问题可能出在此代码中:

bool work_callback(std::string str)
{
   std::cout << str << std::endl;
}

在C ++中,如果非void函数不返回值,则结果是未定义的行为。

此示例将以clang崩溃,但以gcc传递。

如果helper::work_callback返回(例如true),则代码仅在fine下起作用。

答案 1 :(得分:1)

我不知道为什么您的代码段错误,因为我被宠坏了,直接std::bind跳到了lambda。由于您使用C++11,因此您应该将代码从std::bind转换为lambda:

struct worker
{
   std::function<bool(std::string)> m_callback;

   void do_work(std::function<bool(std::string)> callback)
   {
      m_callback = callback;
      callback("hello world\n");
   }
};

现在使用work_callback并调用do_work的事物需要进行一些分析。

第一版:

struct helper
{
   worker the_worker;
   bool work_callback(std::string)
   {
      return false;
   }
};

int main()
{
   helper the_helper;
   the_helper.the_worker.do_work([&](std::string s) { return the_helper.work_callback(s); });
}

现在此版本可用于您的玩具示例。但是在野外,您需要小心。传递给do_work然后存储在the_worker中的lambda通过引用捕获the_helper。这意味着仅当传递给lambda的引用的helper对象超过存储worker的{​​{1}}对象时,此代码才有效。在您的示例中,m_callback对象是worker类的子对象,因此为true。但是,如果在您的实际示例中不是这样,或者您无法证明这一点,那么您需要按价值来捕获。

首次尝试按值捕获(不编译):

helper

这不会编译,因为默认情况下,存储在lambda对象中的struct helper { worker the_worker; bool work_callback(std::string) { return false; } }; int main() { helper the_helper; the_helper.the_worker.do_work([=](std::string s) { return the_helper.work_callback(s); }); } 的副本为the_helper,因此您无法对其调用const

如果您无法使work_callback成为常量,则一个有问题的解决方案是使lambda为work_callback

mutable

但是您需要考虑这是否是您想要的。

更有意义的是使struct helper { worker the_worker; bool work_callback(std::string) { return false; } }; int main() { helper the_helper; the_helper.the_worker.do_work([=](std::string s) mutable { return the_helper.work_callback(s); }); } 成为常量:

work_callback

答案 2 :(得分:1)

评论中已经提到获得SEGFAULT的原因。

但是,我想指出的是,在您给定的情况下,您无需使用都不 std::bind 也不 std::function。相反,只需拥有lambdafunction pointer,您就可以处理您打算做的事情。

struct worker
{
    typedef bool(*fPtr)(const std::string&); // define fun ptr type 
    fPtr m_callback;
    void do_work(const std::string& str)
    {
        // define a lambda
        m_callback = [](const std::string& str)
        { 
            /* do something with string*/ 
            std::cout << "Call from worker: " << str << "\n";
            return true;
        }; 
        bool flag = m_callback(str);// just call the lambda here
        /* do some other stuff*/ 
    }
};

struct helper 
{
    worker the_worker;
    bool work_callback(const std::string& str)
    {
        std::cout << "Call from helper: ";
        this->the_worker.do_work(str);
        return true; ------------------------>// remmeber to keep the promise
    }
};

用例为:

int main()
{
    helper the_helper;
    the_helper.work_callback(std::string("hello world"));

    // or if you intend to use

    the_helper.the_worker.do_work(std::string("hello world"));

    return 0;
}

请参见 Output here


PS :在上述情况下,如果以后的情况(例如,仅worker不需要m_callbackdo_work(),则可以删除该成员,因为可以在声明lambda的位置创建并调用它。

struct worker
{
    void do_work(const std::string& str)
    {
        bool flag = [](const std::string& str)->bool
        { 
            /* do something with string*/ 
            std::cout << "Call from worker: " << str << "\n";
            return true; 
        }(str); -------------------------------------> // function call
        /* do other stuff */
    }
};