當std::bind遇到非靜態類成員函數

之前看項目代碼在實現表驅動方法時,經常會遇到這樣的代碼:

// enum { ID0, ID1, ID2 };
// std::map<int, std::function<void()>> Foo::m;
// void Foo::func0(){}
// void Foo::func1(){}
// void Foo::func2(){}

void Foo::init()
{
    m[ID0] = std::bind(&Foo::func0, this);
    m[ID1] = std::bind(&Foo::func1, this);
    m[ID2] = std::bind(&Foo::func2, this);
}

時間長了以後,我一度認爲std::bind的第一個參數是一個非靜態類成員函數時,第二個參數只能是相應類對象的指針,因爲一直以來都有非靜態類成員函數的第一個參數是隱含的this指針的說法。直到遇到下面的代碼:

    asio::async_write(socket_, asio::buffer(message_),
        boost::bind(&tcp_connection::handle_write, shared_from_this(),
          asio::placeholders::error,
          asio::placeholders::bytes_transferred));

第二個參數還能是std::shared_ptr???

打開https://zh.cppreference.com/w/cpp/utility/functional/bind後才發現,第二個參數可接受的類型遠比我想象的多,第二個函數不但能接受對象指針,還可以接受對象引用,甚至是另一個std::bind返回的可調用對象,下面是代碼:

#include <iostream>
#include <functional>

class Foo
{
public:
    Foo(int key) : m_key(key)
    {}
    void print()
    {
        std::cout << "key: " << m_key << std::endl;
    }
    static Foo create(int key)
    {
        Foo result(key);
        return result;
    }

private:
    int m_key;
};

template<typename T>
class PtrWrapper
{
public:
    PtrWrapper(T *p) : m_p(p)
    {}
    T &operator*()
    {
        return *m_p;
    }

private:
    T *m_p;
};

int main()
{
    // 綁定到指針
    Foo foo0(0);
    auto f0 = std::bind(&Foo::print, &foo0);
    f0();

    // 綁定到對象
    Foo foo1(1);
    auto f1 = std::bind(&Foo::print, foo1);
    f1();

    // 綁定到對象引用
    Foo foo2(2);
    auto f2 = std::bind(&Foo::print, std::ref(foo2));
    f2();

    // 綁定到另一個可調用對象
    auto f3 = std::bind(&Foo::print, std::bind(&Foo::create, std::placeholders::_1));
    f3(3);

    // 綁定到placeholder
    Foo foo4(4);
    auto f4 = std::bind(&Foo::print, std::placeholders::_1);
    f4(foo4);

    // 綁定到實現了T &operator*()的對象
    Foo foo5(5);
    PtrWrapper<Foo> pw(&foo5);
    auto f5 = std::bind(&Foo::print, pw);
    f5();

    return 0;
}

我總結出了6類情況,具體類別可見代碼中的註釋。std::shared_ptr對應的是最後一種情況。

感覺好麻煩,還是用lambda表達式吧。

發佈了98 篇原創文章 · 獲贊 75 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章