(Forward) C++11 functional

转发自Queena为learning circle准备的Blog. 原文地址:C++11 Functional

##c++11 functional

###std::function
function is a template. As with other templates we’ve used, we must specify return type and argument types when we create a function type.
e.g. function

  • C++98 Function pointers and member function pointers
    1. Exact parameter/return types must be specified.
    2. Can’t point to nonstatic member functions.
    3. Can’t point to function objects.
  • boost::function
    1. Using for function, member functions and function objects.
    2. Useful for callback function.
  • C++11 std::function
    1. Using for callable entities that can be called like a function.
      • Functions, function points, function references.
      • Object implicitly convertible to one of those.
      • Function object.
    2. Useful to be able to refer to any callable entity compatible with a given calling interface.

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <functional>
int add(int i, int j)
{
return i +j;
}
int (*addPoint)(int, int) = add;
auto mod = [](int i, int j) {return i % j;};
class Div {
public:
int operator () (int i, int j) {
return i / j;
}
};
class Operation{
public:
int minus(int num1, int num2) { return num1 - num2; }
//int information = 99;
};
int main() {
std::function<int(int, int)> f1 = add; //user-defined function
std::function<int(int, int)> f2 = addPoint; //function pointer
std::function<int(int, int)> f3 = Div(); //user-defined class object with overloadding the fuction-call operator.
std::function<int(int, int)> f4 = std::minus<int>(); //library function object
std::function<int(int, int)> f5 = [](int i, int j){return i*j;}; //unamed lambda
std::function<int(int, int)> f6 = mod; //named lambda object
Operation operation;
std::function<int(int, int)> f7 = std::bind(&Operation::minus,
operation,
std::placeholders::_1,
std::placeholders::_2);//a call of std::bind
std::function<int(Operation&, int, int)> f8 = &Operation::minus; //member function
std::function<int(Operation*, int, int)> f9 = &Operation::minus; //member function
}
std::cerr<<f1(4,2)<<std::endl;
std::cerr<<f2(4,2)<<std::endl;
std::cerr<<f3(4,2)<<std::endl;
std::cerr<<f4(4,2)<<std::endl;
std::cerr<<f5(4,2)<<std::endl;
std::cerr<<f6(4,2)<<std::endl;
std::cerr<<f7(4,2)<<std::endl;
std::cerr<<f8(operation,4,2)<<std::endl;
std::cerr<<f9(&operation,4,2)<<std::endl;

std::bad_function_call is the type of the exception thrown by std::function::operator() if the function wrapper has no target.

example:

1
2
3
4
5
6
std::function<int()> f = nullptr;
try {
f();
} catch(const std::bad_function_call& e) {
std::cout << e.what() << '\n';
}

Reference: std::functionn

###std::mem_fn

To use function, we must supply the call signature of the member we want to call. We can, instead, let the compiler deduce the member’s type
by using another library facility,mem_fn, whick like function, is defined in the functional header.Like function, mem_fn generates a callable
object from a pointer to member. Unlike function, mem_fn will deduce the type of callable from the type of the pointer to member.

  • C++98 std::mem_fun/mem_fun_ref
    1. Only can deal with member functions with one or no argument.
    2. You should pick between both depending on which you want to deal with pointer or reference for class object.
    3. Do not support smart pointer.
  • boost::mem_fn
    _boost::memfn is ageneralization of the _std::mem_fun/mem_funref. It support member function pointers with more than one argument, and support
    smart poiter.
  • C++11 std::mem_fn
    Similar with _boost::memfn. The name is quite confusing!(mem_fun Vs mem_fn)
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
struct Foo {
void displayGreeting() {
std::cout << "Hello, world.\n";
}
void displayNumber(int i) {
std::cout << "number: " << i << '\n';
}
int dataValue() {
return data;
}
int data;
};
int main {
Foo foo;
foo.data = 100;
// member function without parameter
auto f1 = std::mem_fn(&Foo::displayGreeting);
f1(foo);
// member function with parameter
auto f2 = std::mem_fn(&Foo::displayNumber);
f2(foo, 55);
// member varibale
auto data = std::mem_fn(&Foo::data);
std::cout << "data: " << data(foo) << '\n';
// member function that return int
auto f3 = std::mem_fn(&Foo::dataValue);
auto f4 = std::mem_fn<int()>(&Foo::dataValue);
std::cout << "data: " << f3(foo) << '\n';
std::cout << "data: " << f4(foo) << '\n';
}

Reference: std::mem_fn

###std::bind

The bind can be thought of as a general-purpose function adaptor. It takes a callable object and generates a new callable that “adapts” the
parameter list of the original object. The general form of a call to bind is:
auto newCallable = bind(Callable, _arglist);

  • C++98 std::bind1st/std::bind2nd
    bind1st(op, value) op(value, param) and bind2nd(op, value) op(param, value). op is a binary functor, and bind1st/bind2nd actually make the
    binary functor to unary functor. bind1st bind the fist parameter and bind2nd bind the sencond one. Not flexible!
    1. Bind only first or second arguments.
    2. Bind only one argument at a time.
    3. Can’t bind functions with reference parameters.
    4. Require adaptable function objects. i.e._ptrfun, _memfun, and mem_funref.
  • boost::bind
    boost:::bind is generalization of the c++98 std::bin1st/std::bind2nd. It supports arbitrary function objects, function, function pointer, and
    member function pointers, and is able to bind any argument to a specific value or route input arguments into arbitrary positions. bind does not place
    any requirements on the function object; in particular. Mostly it can bind 9 parameters.
  • c++11 std::bind
    Similar with the boost::bind.
    1. functionObject std::bind(_callableEntity, 1stArgBinding, 2ndArgBinding… nthArgBinding); There’s no limit for binding parameters’ number.
    2. _1 is in namespace std::placeholders.

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
int info(std::string& name, int age, double high, double weight) {
std::cout<<"--------Info-----------"<<std::endl;
std::cout<<"name: "<<name<<std::endl;
std::cout<<"age: "<<age<<std::endl;
std::cout<<"high: "<<high<<std::endl;
std::cout<<"weight: "<<weight<<std::endl;
return age;
}
double high(double high) {
return high;
}
struct Foo {
void displayGreeting() {
std::cout << "Hello, world.\n";
}
void displayNumber(int i) {
std::cout << "number: " << i << '\n';
}
int dataValue() {
return data;
}
int data;
};
int main {
std::string lily = "Lily";
// like the lily and 160.6 is pass by value
// like std::placeholders::_1 pass by reference
std::bind<int>(info, std::placeholders::_1, 18, std::placeholders::_2, std::placeholders::_2)(lily, 160.6);
auto f1 = std::bind(info, std::placeholders::_1, 18, std::placeholders::_2, std::placeholders::_2);
f1(lily, 160.6);
// nested bind
auto f2 = std::bind(high, std::placeholders::_1)(160.6);
std::bind(info, lily, std::placeholders::_1, f2, std::placeholders::_2)(18, 160.6);
// nested bind subexpressions share the placeholders
std::bind(info, lily, std::placeholders::_1, std::placeholders::_2, std::bind(high, std::placeholders::_2))(18, 160.6);
//bind to a member function object
Foo foo;
auto f3 = std::bind(&Foo::displayNumber, foo, std::placeholders::_1);
// bind pointer
Foo* pfoo;
auto f4 = std::bind(&Foo::displayNumber, pfoo, std::placeholders::_1);
// bind smart pointer
std::shared_ptr<Foo> spfoo;
auto f5 = std::bind(&Foo::displayNumber, spfoo, std::placeholders::_1);
// bind uniqu pointer.(std::unique_ptr must be wrapped by std::ref when bound,
// because std::unique_ptr isn’t copyable.)
std::unique_ptr<Foo> upfoo;
auto f6 = std::bind(&Foo::displayNumber, std::ref(upfoo), std::placeholders::_1);
// bind member varibale
foo.data = 77;
auto f7 = std::bind(&Foo::data, std::placeholders::_1);
f3(100);
f4(100);
f5(100);
f6(100);
std::cout<< f7(foo) << std::endl;
}

Reference: std::bind

###std::ref/cref
Function templates ref and cref are helper functions that generate an object of type std::reference_wrapper, using template argument deduction to
determine the template argument of the result.

example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void fun(int& n1, int& n2, const int& n3) {
std::cout<< "In function" << n1 << " " << n2 << " " << n3 <<std::endl;
++n1;
++n2;
}
int main {
int n1 =1, n2 = 2, n3 =3;
std::function<void()> f1 = std::bind(fun, n1, std::ref(n2), std::cref(n3));
std::cout<<"Before: "<<n1 <<" "<<n2<< " "<< n3 <<std::endl;
f1();
std::cout<<"After: "<<n1 <<" "<<n2<< " "<< n3 <<std::endl;
}

output:

1
2
3
Before: 1 2 3
In function1 2 3
After: 1 3 3

Reference: std::ref/cref