~~~~我的生活,我的点点滴滴!!
std::function 和 std::bind
标准库函数bind()和function()定义于头文件<functional>中(该头文件还包括许多其他函数对象),用于处理函数及函数参数。类模版 std::function 是一种通用、多态的函数封装。
function
std::function 的实例可以对任何可以调用的 目标 进行存储、复制、和调用操作,这些目标包括函数、lambda 表达式、绑定表达式、以及其它函数对象等。
看下面的例子:
#include <functional>
#include <iostream>
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';
}
int main()
{
// 保存自由函数
std::function<void(int)> f_display = print_num;
f_display(-9);
// 保存 lambda 表达式
std::function<void()> f_display_42 = []() { print_num(42); };
f_display_42();
// 保存 std::bind 的结果
std::function<void()> f_display_31337 = std::bind(print_num, 31337);
f_display_31337();
// 保存成员函数
std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
Foo foo(314159);
f_add_display(foo, 1);
}
输出:
-9
42
31337
314160
bind
bind()接受一个函数(或者函数对象,或者任何你可以通过”(…)”符号调用的事物),生成一个其有某一个或多个函数参数被“绑定”,
要绑定的参数被复制或移动的,并且永远不会通过引用传递,除非包裹在std::ref或std::cref重复在相同的绑定表达式的占位符(多_1的例子)是允许的,
但结果却只有明确定义,如果相应的参数(u1)是一个左值或不可移动的右值。
#include <random>
#include <iostream>
#include <functional>
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()
{
using namespace std::placeholders;
// 传值用引用方式 std::cref(n)
int n = 7;
auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);
n = 10;
// 1 被绑定为_1, 2 被绑定为_2, 1001没用
f1(1, 2, 1001);
// 潜入表达式,可以共享占用符
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
f2(10, 11, 12);
// 绑定到普通成员函数
Foo foo;
auto f3 = std::bind(&Foo::print_sum, foo, 95, _1);
f3(5);
// 绑定到普通成员变量
auto f4 = std::bind(&Foo::data, _1);
std::cout << f4(foo) << '\n';
}
输出:
2 1 42 10 7
12 12 12 4 5
100
10
注:
std::ref()表示传引用
std::cref()表示传不变引用
特别注意:
bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的
bind对于预先绑定的函数参数是通过值传递的
看下面一段代码就知道了
#include <iostream>
using namespace std;
class A
{
public:
void fun_3(int k,int m)
{
cout<<k<<" "<<m<<endl;
}
};
void fun(int x,int y,int z)
{
cout<<x<<" "<<y<<" "<<z<<endl;
}
void fun_2(int &a,int &b)
{
a++;
b++;
cout<<a<<" "<<b<<endl;
}
int main(int argc, const char * argv[])
{
auto f1 = bind(fun,1,2,3); //表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3
f1(); //print:1 2 3
auto f2 = bind(fun, placeholders::_1,placeholders::_2,3);
//表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f2 的第一,二个参数指定
f2(1,2);//print:1 2 3
auto f3 = bind(fun,placeholders::_2,placeholders::_1,3);
//表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f3 的第二,一个参数指定
//注意: f2 和 f3 的区别。
f3(1,2);//print:2 1 3
int n = 2;
int m = 3;
auto f4 = bind(fun_2, n,placeholders::_1);
f4(m); //print:3 4
cout<<m<<endl;//print:4 说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的
cout<<n<<endl;//print:2 说明:bind对于预先绑定的函数参数是通过值传递的
A a;
auto f5 = bind(&A::fun_3, a,placeholders::_1,placeholders::_2);
f5(10,20);//print:10 20
std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);
fc(10,20);//print:10 20
return 0;
}
看一段代码:
#include <functional>
#include <iostream>
void f(int& n1, int& n2, const int& n3)
{
std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
++n1; // increments the copy of n1 stored in the function object
++n2; // increments the main()'s n2
// ++n3; // compile error
}
int main()
{
int n1 = 1, n2 = 2, n3 = 3;
std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));
n1 = 10;
n2 = 11;
n3 = 12;
std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
bound_f();
std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
}
输出:
Before function: 10 11 12
In function: 1 11 12
After function: 10 12 12
从上面看出,其实绑定时,按值已经传递好了,是不会在更改的,但是如果使用了ref与cref,他们按地址传递,就能更改其值。
参照 c++ 官网 http://zh.cppreference.com/w/cpp/utility/functional/
如果 在最后面加上 function (http://zh.cppreference.com/w/cpp/utility/functional/function)他就会跳转到function说明
如果 加上bind 就会跳转到bind说明。