当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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章