簡體   English   中英

將另一個類的成員函數傳遞給 std::function 參數

[英]Passing a member function of another class into a std::function parameter

我有一個帶有一個函數的類,它接受一個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)

正如@Rakete1111 在評論中所指出的,問題可能出在這段代碼中:

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

在 C++ 中,如果非空函數不返回值,則結果是未定義的行為。

這個例子會因clang而崩潰,但會通過gcc

如果helper::work_callback返回(例如, true ),則代碼工作正常

我不知道為什么你的代碼段錯誤,因為我被寵壞了,直接跳過了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); });
}

現在此版本適用於您的玩具示例。 然而,在野外你需要小心。 傳遞給do_work然后存儲在the_worker the_helper通過引用捕獲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); });
}

獲得SEGFAULT的原因已經在評論中提到了。

但是,我想指出的是,在您的給定情況下,您既不需要使用std::bind也不需要使用std::function 相反,只需擁有一個lambda和一個函數指針,您就可以處理您打算做的事情。

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

請參閱此處的輸出


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 */
    }
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM