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

问题描述 投票:-2回答:3

我有一个带有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
}

我得到了一个段错误,但我不确定为什么。我之前使用过这个,事实上,我从另一个地方复制了这个例子。唯一真正的区别是成员函数是我所称的类的一部分(即this而不是the_helper)。

所以这就是为什么我也在问我是否还有其他一些错误?我应该像以下一样通过std::function

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

要么

void do_work(std::function<bool(std::string)>& callback)
c++ class c++11 function-pointers std-function
3个回答
1
投票

正如@ Rakete1111在评论中所指出的,问题可能在于此代码:

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

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

这个例子将与clang崩溃但通过gcc

如果helper::work_callback返回(例如,true),则代码仅适用于fine


1
投票

我不知道为什么你的代码会出错,因为我被宠坏了并且跳过std::bind直接到lambdas。既然你使用C++11,你应该真正将代码从std::bind转换为lambdas:

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); });
}

现在这个版本适用于您的玩具示例。然而,在野外,你需要小心。 lambda传递给do_work,然后存储在the_worker中,通过引用捕获the_helper。这意味着只有当作为lambda引用传递的helper对象超过存储workerm_callback对象时,此代码才有效。在你的例子中,worker对象是helper类的子对象,所以这是真的。但是,如果在您的真实示例中并非如此,或者您无法证明这一点,那么您需要按值捕获。

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

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); });
}

这不能编译,因为默认情况下存储在lambda对象中的the_helper副本是const,因此你不能在它上面调用work_callback

一个可疑的解决方案,如果你不能使work_callback const是使lambda 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 const:

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

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

1
投票

获得SEGFAULT的原因已在评论中提及。

但是,我想指出,在你的情况下,你需要既不使用std::bind也不使用std::function。相反,只需要一个lambda和一个function 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_callback(例如,仅用于do_work()),那么你可以删除这个成员,因为lambdas可以在声明它的同一个地方创建和调用。

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 */
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.