std::function与std::bind
Published on
std::function
类模板std::function是通用多态函数封装器。std::function的实例能存储、复制及调用任何可调用目标,包括:
- 函数/函数指针
- 函数对象
- lambda表达式
- 成员函数指针
- 数据成员指针
作用
- 调用者可使用统一的方式调用可调用目标,无需关心绑定的具体类型
- 一种类型的std::function对象可绑定多种类型的可调用目标,实现多态的效果(例如用于回调函数)
例子
struct Foo
{
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_ + i << '\n'; }
int num_;
};
void print_num(int i)
{
std::cout << i << '\n';
}
struct PrintNum
{
void operator()(int i) const
{
std::cout << i << '\n';
}
};
int main()
{
// 存储函数
std::function<void(int)> f1 = print_num;
f1(-9);
// 存储lambda表达式
std::function<void()> f2 = []() { print_num(42); };
f2();
// 存储std::bind的结果
std::function<void()> f3 = std::bind(print_num, 31337);
f3();
// 存储成员函数指针
std::function<void(const Foo &, int)> f4 = &Foo::print_add;
const Foo foo(314159);
f4(foo, 1);
f4(314159, 1);
// 存储数据成员指针
std::function<int(Foo const &)> f5 = &Foo::num_;
std::cout << f5(foo) << '\n';
// 存储成员函数指针,绑定对象
using std::placeholders::_1;
std::function<void(int)> f6 = std::bind(&Foo::print_add, foo, _1);
f6(2);
// 存储成员函数指针,绑定对象指针
std::function<void(int)> f7 = std::bind(&Foo::print_add, &foo, _1);
f7(3);
// 存储函数对象
std::function<void(int)> f8 = PrintNum();
f8(18);
}
std::bind
std::bind函数将可调用目标与指定参数进行绑定,并以函数对象的形式保存。调用此函数对象相当于使用绑定的参数调用原可调用目标。如果有的参数不能在绑定时确定,可以使用std::placeholders中的占位符占位,并延迟到调用时再传入。
作用
- 提前将参数绑定,调用时无需再次传入,并且可以多次调用
- 将一个可调用目标的接口形式转换成另一种形式,以适应某种接口要求(如注册回调函数)
例子
void f(int n1, int n2, int n3, const int &n4, int n5)
{
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
int g(int n1)
{
return n1;
}
struct Foo
{
void print_sum(int n1, int n2)
{
std::cout << n1 + n2 << '\n';
}
int data = 10;
};
int main()
{
// 占位符,如_1, _2, _3...
using namespace std::placeholders;
// 参数重排序与按引用传递
int n = 7;
auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
n = 10;
// 相当于调用f(2, 42, 1, n, 7),1001未使用
f1(1, 2, 1001);
// 使用lambda表达式达成相同效果
n = 7;
auto lambda = [&ncref = n, n](auto a, auto b, auto /*未使用*/)
{
f(b, 42, a, ncref, n);
};
n = 10;
// 相当于调用f(2, 42, 1, n, 7),1001未使用
lambda(1, 2, 1001);
// 嵌套bind子表达式共享占位符
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
// 相当于调用f(12, g(12), 12, 4, 5)
f2(10, 11, 12);
// 绑定成员函数指针
Foo foo;
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
f3(5);
// 绑定成员函数指针的mem_fn
auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1);
f4(5);
// 绑定数据成员指针
auto f5 = std::bind(&Foo::data, _1);
std::cout << f5(foo) << '\n';
// 绑定数据成员指针的mem_fn
auto ptr_to_data = std::mem_fn(&Foo::data);
auto f6 = std::bind(ptr_to_data, _1);
std::cout << f6(foo) << '\n';
// 使用智能指针调用被引用对象的成员
std::cout << f6(std::make_shared<Foo>(foo)) << ' '
<< f6(std::make_unique<Foo>(foo)) << '\n';
}