C++11 std::bind
1. 介绍
std::bind
是C++11由Boost引进的函数适配器。它以函数作为输入参数,返回一个函数对象,输入函数的一个或者多个参数可以被绑定。
2. 使用
std::bind
可以用于绑定很多对象,包括:函数,类的成员函数,类的成员变量的指针等。以下举几个简单的例子来展示它的用法。
2.1 绑定函数
#include <iostream>
#include <functional>
int add(int a, int b, int& c)
{
return a+b+c;
}
int main()
{
int c = 10;
auto f = std::bind(add, 1, 2, c);
}
2.2 绑定类的成员变量的指针
#include <iostream>
#include <functional>
class Foobar
{
public:
int m_;
};
int main()
{
Foobar foobar;
foobar.m_ = 123;
auto f = std::bind(&Foobar::m_, &foobar); //注意:这里第一个参数传的是类的成员函数的地址
//第二个传的是实例的地址(如果直接传实例会调用其拷贝构造函数)
std::cout << f() << std::endl;
}
输出:123
2.3 绑定类的成员函数
#include <iostream>
#include <functional>
using namespace std::placeholders;
class Foobar
{
public:
Foobar():
value_(0)
{}
Foobar(const Foobar &o):
value_(0) // reset value to 0
{
std::cout << "Foobar: copy C'tor" << std::endl;
}
int setValue(int v)
{value_ = v;}
int printValue()
{
std::cout << value_ << "(caller: " << std::showbase << this << ")" << std::endl;
}
private:
int value_;
};
int main()
{
Foobar foobar;
foobar.setValue(100);
// If pass object to bind(), the copy C'tor will be called.
// A new object is constructed.
std::cout << "\nPassing Object: " << std::endl;
auto f = std::bind(&Foobar::printValue, foobar);
f();
std::cout << "\nPassing pointer: " << std::endl;
auto ff = std::bind(&Foobar::printValue, &foobar);
ff();
std::cout << "\nPassing reference: " << std::endl;
auto fff = std::bind(&Foobar::printValue, std::ref(foobar));
fff();
}
输出:
Passing Object:
Foobar: copy C'tor
0(caller: 0x7ffef109ad70)
Passing pointer:
100(caller: 0x7ffef109ad30)
Passing reference:
100(caller: 0x7ffef109ad30)
引用cppreference中关于bind的说明:
As described in Callable, when invoking a pointer to non-static member function or pointer to non-static data member, the first argument has to be a reference or pointer (including, possibly, smart pointer such as std::shared_ptr and std::unique_ptr) to an object whose member will be accessed.
The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.
所以上面的例子中,在传入第一个参数的时候,第一个例子中传入的是foobar
对象本身,于是会调用Foobar类的拷贝构造函数来构造一个新的对象,这往往是不希望发生的;而第二个和第三个例子中传入的是foobar
的指针和引用,前者是指传递(传递指针,也就是地址),后者是传递引用。在调用发生的时候都会调用foobar
中的函数。
另外一个例子是将一个类(A)中的函数设置到另一个类(B),作为类B对A的callback函数:
#include <iostream>
#include <functional>
class Worker
{
public:
Worker():
callback_(nullptr)
{}
void doSomething()
{
/* doing something... */
callback();
}
void callback()
{
if (callback_ != nullptr)
callback_();
}
void setCallback(std::function<void()> f)
{
callback_ = f;
}
private:
std::function<void()> callback_;
};
class Interface
{
public:
void notify()
{
std::cout << "Notify outside world some event" << std::endl;
}
};
class Manager
{
public:
Manager():
worker_(),
interface_()
{
worker_.setCallback(std::bind(&Interface::notify, &interface_));
}
void doSomething()
{
worker_.doSomething();
}
private:
Interface interface_;
Worker worker_;
};
int main()
{
Manager mgr;
mgr.doSomething();
}
输出:Notify outside world some event
3. 引用
[1] std::bind – Tutorial and Examples
[2] boost bind.hpp
[3] cppreference
Comments