【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 }
View Code

 

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 }
View Code

输出结果:

 

  • std::bind使用的是参数的拷贝而不是引用,当可调用对象期待入参为引用时,必须显示利用std::ref来进行引用绑定
  • 多线程std::thread的可调用对象期望入参为引用时,也必须显式通过std::ref来绑定引用进行传参

 

参考资料

 

1. std::bind 的用法

 

posted @ 2019-03-20 20:44  苏格拉底的落泪  阅读(523)  评论(0编辑  收藏  举报