2.5.11 Functions

What was the problem

Storing functions in a variable in C++ used to be a pain. For example, how would we implement callable such that the code below works?

void foo(); 
void bar(int arg); 
 
struct some_object 
{ 
  void some_method(); 
}; 
 
void test(); 
{ 
  std::vector<callable> scheduled; 
 
  scheduled.push_back(&foo); 
  // bar with arg = 5. 
  scheduled.push_back(std::bind(&bar, 5)); 
 
  some_object c; 
  scheduled.push_back(std::bind(&some_object::some_method, &c)); 
 
  // All stored functions can be called as if they were void(). 
  scheduled[0](); 
  scheduled[1](); 
  scheduled[2](); 
}

Having a working type for all these use cases is a huge task, and before C++11 our only hope were Boost.Function, some other libraries13, or and homemade solution.

A binding like presented in Section 2.5.8 is a partial answer to that but first, it does not even handle member functions, and two, it is already C++11.

How the Problem is Solved

PIC <utility>

The std::function type introduced in C++11, in combination with std::bind [?? ], is exactly what we need to fix our previous example. The former is an object that represents a function, and that can be called to invoke this function. It can be a function object or a free function, everything works.

void foo(); 
void bar(int arg); 
 
struct some_object 
{ 
  void some_method(); 
}; 
 
void test(); 
{ 
  std::vector<std::function<void()>> scheduled; 
 
  scheduled.push_back(&foo); 
  // bar with arg = 5. 
  scheduled.push_back(std::bind(&bar, 5)); 
 
  some_object c; 
  scheduled.push_back(std::bind(&some_object::some_method, &c)); 
 
  // All stored functions can be called as if they were void(). 
  scheduled[0](); 
  scheduled[1](); 
  scheduled[2](); 
}

As far as can tell there is only one downside to std::function, it is that every call begins with a test checking if a function is set. If we care about performance, it can be an issue14.

13Search for FastDelegate, the Impossibly Fast C++ Delegates, More Fasterest Delegates, and Ultimate Fast C++ Delegates II’. Some of them may not exist.

14This test is used to throw an std::bad_function_call if the invocation is done on an empty instance. If you wonder why std::function does not reference by default a function that throws the exception, such that no test is done and the exception is still thrown when an empty function is invoked, know that I wonder too. If you have insight about it, I would love to know.