【问题标题】:Passing a member function of another class into a std::function parameter将另一个类的成员函数传递给 std::function 参数
【发布时间】:2025-11-28 23:35:02
【问题描述】:

我有一个类,其函数接受 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)

【问题讨论】:

  • @AMA 抱歉 - typeo - 已修复
  • 手工复制代码更大的问题是,当所有的错别字都被修正后,问题就不会再次出现coliru.stacked-crooked.com/a/f68ad0b1afc252f9
  • @StoryTeller 删除你在其中的return false; 并享受那个段错误:P @OP 你能确认一下吗?
  • 您花时间创建了问题的精简版。这是极好的。你做了可以说是最难的部分。但是您需要创建minimal reproducible example。只需您付出一点努力,您就可以获得一段我们可以复制粘贴和编译的代码。因为它是您的代码无法编译,您将失去愿意提供帮助但不愿意做您的部分的人 - 这是正确的方法。请帮助自己并创建一个 MCVE。
  • @Rakete1111 - 好吧,我把酒杯举到-pedantic-errors

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


【解决方案1】:

@Rakete1111 在 cmets 中也指出,问题可能出在以下代码中:

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

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

此示例将在 clang 时崩溃,但在 gcc 时会通过。

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

【讨论】:

  • 这是一个有效的点。但这不是我问题的原因。我的问题并没有在 MCVE 中体现...但是通过编写它确实帮助我找到了问题 the_helper 应该是 &amp;the_helper
【解决方案2】:

我不知道为什么你的代码段错误,因为我被宠坏了,直接跳过了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 对象比存储 m_callbackworker 对象的寿命更长时才有效。在您的示例中,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); });
}

【讨论】:

    【解决方案3】:

    获取SEGFAULT的原因在cmets中已经提到了。

    但是,我想指出,在您给定的情况下,您需要使用 既不 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_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 */
        }
    };
    

    【讨论】: