std::function for functors

The std::function and boost::function work in the same way. So, if your compiler does not support C++0x yet, you could get exactely the same behaviour shown here using boost. Just remeber to include the required header file:
#include "boost/function.hpp"

The point of this post is showing how using std::function we can do all what we can do using function pointers, but the viceversa is not true. For instance, std::function could accept functor as argument.

Let's say we want to develop a class, Notifier, to call back the functions we register on it any time its state change.

A first implementation uses a vector of function pointers. And it works fine.

The problem is if we want to use functors, too. The reason is quite clear, a functor gives us more power, since it could keeps its own internal status.

But that requires we redesign our class, using std::function instead. We call it NotifierExt. We see that the change in the code is minimal, and the advantage is self evident, I think.

Here is the code:

#include <iostream>
#include <vector>
#include <functional>

namespace
{
void printNewValue(int i)
{
std::cout << "The value has been updated and is now " << i << std::endl;
}

void changeObserver(int i)
{
std::cout << "Ah, the value has changed!" << std::endl;
}

class PrintPreviousValue
{
int lastValue_;
public:
PrintPreviousValue() : lastValue_(-1) {}

void operator()(int i)
{
std::cout << "Previous value was " << lastValue_ << std::endl;
lastValue_ = i;
}
};

class Notifier
{
typedef void (*FunType)(int);
std::vector<FunType> vec_;
int value_;
public:
void addObserver(FunType t)
{
vec_.push_back(t);
}

void changeValue(int i)
{
value_ = i;
for(size_t i=0; i < vec_.size(); ++i)
vec_[i](value_);
}
};

class NotifierExt
{
typedef std::function<void(int)> FunType;
std::vector<FunType> vec_;
int value_;
public:
void addObserver(FunType t)
{
vec_.push_back(t);
}

void changeValue(int i)
{
value_ = i;
for(size_t i = 0; i < vec_.size(); ++i)
vec_[i](value_);
}
};
}

void function02()
{
std::cout << "Using function pointer" << std::endl;
Notifier n;
n.addObserver(&printNewValue);
n.addObserver(&changeObserver);

n.changeValue(42);

std::cout << "Using std::function" << std::endl;
NotifierExt ne;
ne.addObserver(&printNewValue);
ne.addObserver(&changeObserver);
ne.addObserver(PrintPreviousValue());

ne.changeValue(42);
ne.changeValue(39);
}


The code is based on an example provided by "Beyond the C++ Standard Library: An Introduction to Boost", by Björn Karlsson, an Addison Wesley Professional book. An interesting reading indeed.

No comments:

Post a Comment