C++11: std::function and std::bind

C++11: std::function and std::bind

原文地址:https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/

std::function and std::bind were born inside the Boost C++ Library, but they were incorporated into the new C++11 standard.

std::function is a STL template class that provides a very convenient wrapper to a simple function, to a functor or to a lambda expression.

 

For example, if you want to store several functions, functors or lambda expressions in a vector, you could write something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <functional>
#include <iostream>
#include <string>
#include <vector>
 
using namespace std;
 
void execute(const vector<function<void ()>>& fs)
{
    for (auto& f : fs)
        f();
}
 
void plain_old_func()
{
    cout << "I'm an old plain function" << endl;
}
 
class functor
{
    public:
        void operator()() const
        {
            cout << "I'm a functor" << endl;
        }
};
 
int main()
{
    vector<function<void ()>> x;
    x.push_back(plain_old_func);
     
    functor functor_instance;
    x.push_back(functor_instance);
    x.push_back([] ()
    {
        cout << "HI, I'm a lambda expression" << endl;
    });
     
    execute(x);
}

As you can see, in this declaration:


vector<function<void ()>> x;

we are declaring a vector of functions. The void () part means that the functions do not receive any argument and have void as return type. If you would want to define a function that receives two integers and return an integer too, you should declare your function as:

1
2
3
int my_func(int a, int b) { return a + b; }
 
function<int (int, int)> f = my_func;

The new standard library also adds a new function: std::bindstd::bind is a template function that returns a std::function object that binds a set of arguments to a function.

Consider the first code listing shown in this post, the functions stored in the vector do not receive any argument; but you probably want to store a function that receives more arguments in the same vector. You could do that using std::bind.

Say you have this function:

1
2
3
4
void show_text(const string& t)
{
    cout << "TEXT: " << t << endl;
}

How can you add it into the function of vectors of the first code listing? Add this code the main function:

1
2
function <void ()> f = bind(show_text, "Bound function");
x.push_back(f);

As you can see, the std::bind receives a pointer to a function (it also can be a lambda expression or a functor) and receives a list of parameters that pass it to the function. As result, bind returns a new function object with a different prototype because all the parameters of the function were already specified.

Look at this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <functional>
#include <iostream>
 
using namespace std;
using namespace std::placeholders;
 
int multiply(int a, int b)
{
    return a * b;
}
 
int main()
{
    auto f = bind(multiply, 5, _1);
    for (int i = 0; i < 10; i++)
    {
        cout << "5 * " << i << " = " << f(i) << endl;
    }
        return 0;
}

Look at the usage of std::bind: The first parameter is the pointer to the functionmultiply. The second parameter is the value passed as first parameter to the function multiply. The third parameter is called a “placeholder”. A placeholder is an object that specifies the number of parameter in the bound function that will be used to enter this parameter. So, if you look inside the for loop, you can call f just passing it one parameter.

Thanks to the placeholders, you can change the order of the arguments passed as parameters to a bound function. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <functional>
#include <string>
#include <iostream>
 
using namespace std;
using namespace std::placeholders;
 
void show(const string& a, const string& b, const string& c)
{
    cout << a << "; " << b << "; " << c << endl;
}
 
int main()
{
    auto x = bind(show, _1, _2, _3);
    auto y = bind(show, _3, _1, _2);
    auto z = bind(show, "hello", _2, _1);
     
    x("one", "two", "three");
    y("one", "two", "three");
    z("one", "two");
     
    return 0;
}

The output is:


one; two; three
three; one; two
hello; two; one

posted on 2016-07-04 19:19  ZhYQ_note  阅读(199)  评论(0)    收藏  举报

导航