Queeza Blog

You Dream, We Code.

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<int(int, int)>

  • 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::mem_fn is ageneralization of the std::mem_fun/mem_fun_ref. It support member function pointers with more than one argument, and support smart poiter.
  • C++11 std::mem_fn
    Similar with boost::mem_fn. 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_, _arg_list_);
  • 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.ptr_fun, mem_fun, and mem_fun_ref_.
  • 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