【C++编程】function、bind
bind用法(10)
| 占位符 | 表示 |
|---|---|
_1 |
调用时的第1个参数 |
_2 |
调用时的第2个参数 |
_3 |
第3个参数 |
| ... | ... |
#include <iostream>
#include <functional>
void print(int a, int b) {
std::cout << a << " " << b << std::endl;
}
int main() {
auto f = std::bind(print, 10, std::placeholders::_1);
f(20); // 输出:10 20
}
解释:std::bind(print, 10, _1) 等价于 f(x) => print(10, x)
参数重排:
auto f = std::bind(print,
std::placeholders::_2,
std::placeholders::_1);
f(1, 2); // 输出:2 1
1. 绑定一个普通函数
#include <iostream>
#include <functional>
void print(int a, int b) {
std::cout << a << " " << b << std::endl;
}
int main() {
std::function<void(int)> f =
std::bind(print, 100, std::placeholders::_1);
f(200); // 100 200
}
std::bind绑定一个成员函数
#include <iostream>
#include <functional>
struct Foo {
void print_sum(int n1, int n2) {
std::cout << n1 + n2 << '\n';
}
int data = 10;
};
int main() {
Foo foo;
auto f1 = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1);
f1(5); // 100
std::function<void(int)> f1 = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1);
f2(5); //100
return 0;
}
1 #include <iostream> 2 #include <functional> 3 4 struct Foo 5 { 6 void print_sum(int n1, int n2) 7 { 8 std::cout << n1 + n2 << '\n'; 9 } 10 int data = 10; 11 }; 12 int main() 13 { 14 Foo foo; 15 auto f = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1); 16 f(5); // 100 17 }
- bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址。
- 必须显示的指定&Foo::print_sum,因为编译器不会将对象的成员函数隐式转换成函数指针,所以必须在Foo::print_sum前添加&;
- 使用对象成员函数的指针时,必须要知道该指针属于哪个对象,因此第二个参数为对象的地址 &foo;
绑定成员变量:
class Test {
public:
int value = 42;
};
Test t;
auto f = std::bind(&Test::value, t);
std::cout << f() << std::endl; // 42
3.3 绑定一个引用参数
默认情况下,bind 会拷贝参数。
- std::bind使用的是参数的拷贝而不是引用,当可调用对象期待入参为引用时,必须显示利用std::ref来进行引用绑定。
- 多线程std::thread的可调用对象期望入参为引用时,也必须显式通过std::ref来绑定引用进行传参
如果你想传引用,必须使用:
std::ref(obj)
std::cref(obj)
默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。但是,与lambda类似,有时对有些绑定的参数希望以引用的方式传递,或是要绑定参数的类型无法拷贝。
void modify(int& x) {
x = 100;
}
int main() {
int a = 10;
auto f = std::bind(modify, std::ref(a));
f();
std::cout << a << std::endl; // 100
}
1 #include <iostream> 2 #include <functional> 3 #include <vector> 4 #include <algorithm> 5 #include <sstream> 6 using namespace std::placeholders; 7 using namespace std; 8 9 ostream& print(ostream &os, const string& s, char c) 10 { 11 os << s << c; 12 return os; 13 } 14 15 int main() 16 { 17 vector<string> words{ "helo", "world", "this", "is", "C++11" }; 18 ostringstream os; 19 char c = ' '; 20 for_each(words.begin(), words.end(), 21 [&os, c](const string & s) {os << s << c; }); 22 cout << os.str() << endl; 23 24 ostringstream os1; 25 // ostream不能拷贝,若希望传递给bind一个对象, 26 // 而不拷贝它,就必须使用标准库提供的ref函数 27 for_each(words.begin(), words.end(), 28 bind(print, ref(os1), _1, c)); 29 cout << os1.str() << endl; 30 }
例4:
1 #include <iostream> 2 #include <functional> 3 using namespace std; 4 5 class Computer 6 { 7 public: 8 static int Add(int i, int j) { return i + j; } 9 10 template <class T> 11 static T AddT(T i, T j) { return i + j; } 12 13 int AddN(int i, int j) { return i + j; } 14 }; 15 16 int main() 17 { 18 //1、 类静态函数 19 function<int(int, int)> f = &Computer::Add; 20 cout << f(1, 1) << endl; 21 22 //2、 类静态模板函数 23 function<int(int, int)> ft = &Computer::AddT<int>; 24 cout << ft(1, 1) << endl; 25 26 //普通函数绑定 需要构造类对象 27 Computer c; 28 //3、 普通函数 需使用bind,将类对象地址 &c 绑定上 29 function<int(int, int)> fN = bind(&Computer::AddN, &c, placeholders::_1, placeholders::_2); 30 cout << fN(1, 1) << endl; 31 32 //4、普通函数, 也可以这样调用 个人觉得这个比 bind 麻烦,不建议 33 function<int(const Computer &, int, int)> fN2 = &Computer::AddN; 34 cout << fN2(c, 1, 1) << endl; 35 return 0; 36 }
ref 与 cref 的用法
bind()是一个函数模板,它的原理是根据已有的模板,生成一个函数,但是由于bind()不知道生成的函数执行的时候,传递进来的参数是否还有效。所以它选择参数值传递而不是引用传递。如果想引用传递,std::ref和std::cref就派上用场了。
- std::ref 用于包装按引用传递的值。
- std::cref 用于包装按const引用传递的值。
1 #include <functional> 2 #include <iostream> 3 4 void f(int &n1, int &n2, const int &n3) 5 { 6 std::cout << "In function: n1[" << n1 << "] n2[" << n2 << "] n3[" << n3 << "]" << std::endl; 7 ++n1; // 增加存储于函数对象的 n1 副本 8 ++n2; // 增加 main() 的 n2 9 //++n3; // 编译错误 10 std::cout << "In function end: n1[" << n1 << "] n2[" << n2 << "] n3[" << n3 << "]" << std::endl; 11 } 12 13 int main() 14 { 15 int n1 = 1, n2 = 1, n3 = 1; 16 std::cout << "Before function: n1[" << n1 << "] n2[" << n2 << "] n3[" << n3 << "]" << std::endl; 17 std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3)); 18 bound_f(); 19 std::cout << "After function: n1[" << n1 << "] n2[" << n2 << "] n3[" << n3 << "]" << std::endl; 20 }
输出结果:

- std::bind使用的是参数的拷贝而不是引用,当可调用对象期待入参为引用时,必须显示利用std::ref来进行引用绑定。
- 多线程std::thread的可调用对象期望入参为引用时,也必须显式通过std::ref来绑定引用进行传参。
参考资料
- C++11 中的std::function和std::bind
- std::bind使用的是参数的拷贝而不是引用,当可调用对象期待入参为引用时,必须显示利用std::ref来进行引用绑定。
- 多线程std::thread的可调用对象期望入参为引用时,也必须显式通过std::ref来绑定引用进行传参。
- std::ref和std::cref使用
- C++11 function类模
现在C++用法
bind写法:
std::function<void(int)> f = std::bind(print, 10, std::placeholders::_1);
lambda写法:
std::function<void(int)> f =
[=](int x) {
print(10, x);
};

浙公网安备 33010602011771号