【C++编程】function、bind
bind用法(10)
1 using namespace std; 2 using namespace std::placeholders; 3 4 void f(int s1, int s2, int s3, int s4, int s5) 5 { 6 cout << "s1 = " << s1 << " s2 = " << s2 << " s3 = " << s3 7 << " s4 = " << s4 << " s5 = " << s5; 8 9 } 10 11 int main() 12 { 13 auto g = bind(f, 4, 5, _2, 6, _1); 14 int a, b; 15 cin >> a >> b; 16 g(a, b); 17 return 0; 18 }
1. 绑定一个普通函数
1 #include <iostream> 2 #include <functional> 3 4 int add(int a, int b) { 5 return a + b; 6 } 7 8 int main() { 9 10 auto f1 = std::bind(add, std::placeholders::_1, std::placeholders::_2); 11 std::cout << "f1(5, 7) = " << f1(5, 7) << std::endl; 12 13 std::function<int(int, int)> f2 = add ; 14 std::cout << "f2(5, 7) = " << f2(5, 7) << std::endl; 15 16 return 0; 17 }
2. bind绑定一个成员函数
1 #include <iostream> 2 #include <functional> 3 4 struct Foo { 5 void print_sum(int n1, int n2) { 6 std::cout << n1 + n2 << '\n'; 7 } 8 int data = 10; 9 }; 10 11 int main() { 12 Foo foo; 13 auto f1 = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1); 14 f1(5); // 100 15 16 std::function<void(int)> f1 = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1); 17 f2(5); //100 18 return 0; 19 }
std::function
1. std::bind绑定一个成员函数
#include #include struct Foo { void print_sum( int n1, int n2) { std::cout << n1 + n2 << '\n' ; } int data = 10; }; int main() { Foo foo; auto f = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1); f(5); // 100 }
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;
3.3 绑定一个引用参数
默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。但是,与lambda类似,有时对有些绑定的参数希望以引用的方式传递,或是要绑定参数的类型无法拷贝。
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类模