Beyond the C++ Standard Library: An Introduction to Boost [Electronic resources] نسخه متنی

This is a Digital Library

With over 100,000 free electronic resource in Persian, Arabic and English

Beyond the C++ Standard Library: An Introduction to Boost [Electronic resources] - نسخه متنی

Bjorn Karlsson

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید

Usage


To start using Boost.Function, include "boost/function.hpp", or any of the numbered versions, ranging from "boost/function/function0.hpp" to "boost/function/function10.hpp". If you know the arity of the functions you want to store in functions, it taxes the compiler less to include the exact headers that are needed. When including "boost/function.hpp", the other headers are all included, too.

The best way to think of a stored function is a normal function object that is responsible for wrapping another function (or function object). It then makes perfect sense that this stored function can be invoked several times, and not necessarily at the time when the function is created. When declaring functions, the most important part of the declaration is the function signature. This is where you tell the function about the signature and return type of the functions and/or function objects it will store. As we've seen, there are two ways to perform such declarations. Here's a complete program that declares a boost::function that is capable of storing function-like entities that return bool (or a type that is implicitly convertible to bool) and accept two arguments, the first convertible to int, and the second convertible to double.


#include <iostream>
#include "boost/function.hpp"
bool some_func(int i,double d) {
return i>d;
}
int main() {
boost::function<bool (int,double)> f;
f=&some_func;
f(10,1.1);
}

When the function f is first created, it doesn't store any function. It is empty, which can be tested in a Boolean context or with 0. If you try to invoke a function that doesn't store a function or function object, it throws an exception of the type bad_function_call. To avoid that problem, we assign a pointer to some_func to f using normal assignment syntax. That causes f to store the pointer to some_func. Finally, we invoke f (using the function call operator) with the arguments 10 (an int) and 1.1 (a double). When invoking a function, one must supply exactly the number of arguments the stored function or function object expects.

The Basics of Callbacks


Let's look at how we would have implemented a simple callback before we knew about Boost.Function, and then convert the code to make use of function, and examine which advantages that brings forth. We will start with a class that supports a simple form of callbackit can report changes to a value by calling whoever is interested in the new value. The callback will be a traditional C-style callbackthat is, a free function. This callback could be used, for example, for a GUI control that needs to inform observers that the user changed its value, without having any special knowledge about the clients listening for that information.


#include <iostream>
#include <vector>
#include <algorithm>
#include "boost/function.hpp"
void print_new_value(int i) {
std::cout <<
"The value has been updated and is now " << i << '\n';
}
void interested_in_the_change(int i) {
std::cout << "Ah, the value has changed.\n";
}
class notifier {
typedef void (*function_type)(int);
std::vector<function_type> vec_;
int value_;
public:
void add_observer(function_type t) {
vec_.push_back(t);
}
void change_value(int i) {
value_=i;
for (std::size_t i=0;i<vec_.size();++i) {
(*vec_[i])(value_);
}
}
};
int main() {
notifier n;
n.add_observer(&print_new_value);
n.add_observer(&interested_in_the_change);
n.change_value(42);
}

Two functions, print_new_value and interested_in_the_change, have a signature that is compatible with what the notifier class supports. The function pointers are stored in a vector, and then invoked in a loop whenever the value changes. One syntax for invoking the functions is


(*vec_[i])(value_);

The dereferenced function pointer (which is what is returned from vec_[i]) is passed the value (value_). It's also valid to write the code differently, like this:


vec_[i](value_);

This may seem a bit nicer to the eye, but more importantly, it also allows you to replace the function pointer with Boost.Function without syntactic changes for invocation. Now, this works fine, but alas, function objects don't work at all with this notifier class. Actually, nothing but function pointers work, which is a serious limitation. It would work, however, if we were using Boost.Function. Rewriting the notifier class is fairly straightforward.


class notifier {
typedef boost::function<void(int)> function_type;
std::vector<function_type> vec_;
int value_;
public:
template <typename T> void add_observer(T t) {
vec_.push_back(function_type(t));
}
void change_value(int i) {
value_=i;
for (std::size_t i=0;i<vec_.size();++i) {
vec_[i](value_);
}
}
};

The first thing to do is to change the typedef to refer to boost::function rather than a function pointer. Before, we defined a function pointer; now we are using the generalization, which will soon prove its usefulness. Next, we change the signature of the member function add_observer to be parameterized on the argument type. We could have changed it to accept boost::function instead, but that means that users of our class would need to understand how function works[2] too, rather than just knowing about the requirements for the observer type. It should be duly noted that this change of add_observer is not a result of switching to function; the code would continue to work anyway. We make the change for generality; now, both function pointers, function objects, and instances of boost::function can be passed to add_observer, without any changes to existing user code. The code for adding elements to the vector is slightly altered, and now creates instances of boost::function<void(int)>. Finally, we change the code that invokes the functions to the syntax that can be used for functions, function objects, and instances of boost::function.[3] This extended support for different types of function-like "things" can immediately be put to use with a stateful function object, which represents something that could not be easily done using functions.

[2] They should know about Boost.Function, but what if they don't? Everything that we add to an interface will need to be explained to users at some point in time.

[3] Now we know that we should actually have been invoking like this from the beginning.


class knows_the_previous_value {
int last_value_;
public:
void operator()(int i) {
static bool first_time=true;
if (first_time) {
last_value_=i;
std::cout <<
"This is the first change of value, so I don't know the previous one.\n";
first_time=false;
return;
}
std::cout << "Previous value was " << last_value_ << '\n';
last_value_=i;
}
};

This function object stores the previous value and prints it to std::cout whenever the value changes again. Note that the first time it is invoked, it doesn't know about the previous value. The function object detects this using a static bool variable in the function, which is initially set to true. Because static variables in functions are initialized when the function is first invoked, it is only set to true during the first invocation. Although static variables can be used like this to provide state for free functions too, we must understand that it does not scale well, and is hard to do safely in a multithreaded environment. So, function objects with state are always to be preferred over free functions with static variables. The notifier class doesn't mind this function object at allit complies with the requirements and is therefore accepted. This updated sample program demonstrates how this works.


int main() {
notifier n;
n.add_observer(&print_new_value);
n.add_observer(&interested_in_the_change);
n.add_observer(knows_the_previous_value());
n.change_value(42);
std::cout << '\n';
n.change_value(30);
}

The important line to examine is where we add an observer that isn't a function pointer, but an instance of the function object knows_the_previous_value. Running the program gives the following output:


The value has been updated and is now 42
Ah, the value has changed.
This is the first change of value,
so I don't know the previous one.
The value has been updated and is now 30
Ah, the value has changed.
Previous value was 42

The great advantage here, more than relaxing the requirements on the functions (or rather, the additional support for function objects), is that we can introduce objects with state, which is a very common need. The changes that we made to the notifier class were trivial, and user code wasn't affected at all. As shown here, introducing Boost.Function into an existing design is typically straightforward.

Functions That Are Class Members


Boost.Function does not support argument binding, which would be needed to make each invocation of a function invoke a member function on the same class instance. Fortunately, it is possible to directly call member functions if the class instance is passed to the function. The signature of the function needs to include the type of the class, as well as the signature of the member function. In other words, the class instance is passed explicitly as what would normally be the implicit first parameter, this. The result is a function object that invokes a member function on the supplied object. Consider the following class:


class some_class {
public:
void do_stuff(int i) const {
std::cout << "OK. Stuff is done. " << i << '\n';
}
};

The member function do_stuff is to be called from within an instance of boost::function. To do this, we need the function to accept an instance of some_class, and have the rest of the signature be a void return and an int argument. We have three choices when it comes to deciding how the instance of some_class should be passed to the function: by value, by reference, or by address. To pass by value, here's how the code would look.[4]

[4] There are seldom good reasons for passing the object parameter by value.


boost::function<void(some_class,int)> f;

Note that the return type still comes first, followed by the class where the member function is a member, and finally the arguments to the member function. Think of it as passing this to the function, which is implicitly the case when calling non-static member functions on an instance of a class. To configure the function f with the member function do_stuff, and then invoke the function, we do this:


f=&some_class::do_stuff;
f(some_class(),2);

When passing by reference, we change the signature of the function, and pass an instance of some_class.


boost::function<void(some_class&,int)> f;
f=&some_class::do_stuff;
some_class s;
f(s,1);

Finally, to pass a pointer[5] to some_class, this is how we'd write the code:

[5] Both raw pointers and smart pointers will do.


boost::function<void(some_class*,int)> f;
f=&some_class::do_stuff;
some_class s;
f(&s,3);

So, all the likely variants for passing instances of the "virtual this" are provided by the library. Of course, there is a limitation to this technique: You have to pass the class instance explicitly; and ideally, you'd want the instance to be bound in the function object instead. At first glance, that seems to be a disadvantage of Boost.Function, but there are other libraries that support binding arguments, such as Boost.Bind and Boost.Lambda. We will examine the added value that a collaboration with such libraries brings to Boost.Function later in this chapter.

Stateful Function Objects


We have already seen that it is possible to add state to callback functions, because of the support for function objects. Consider a class, keeping_state, which is a function object with state. Instances of keeping_state remember a total, which is increased each time the function call operator is invoked. Now, when using an instance of this class with two instances of boost::function, the results may be somewhat surprising.


#include <iostream>
#include "boost/function.hpp"
class keeping_state {
int total_;
public:
keeping_state():total_(0) {}
int operator()(int i) {
total_+=i;
return total_;
}
int total() const {
return total_;
}
};
int main() {
keeping_state ks;
boost::function<int(int)> f1;
f1=ks;
boost::function<int(int)> f2;
f2=ks;
std::cout << "The current total is " << f1(10) << '\n';
std::cout << "The current total is " << f2(10) << '\n';
std::cout << "After adding 10 two times, the total is "
<< ks.total() << '\n';
}

When writing, and subsequently running, this program, the programmer probably expects that the total stored in ks is 20, but it's not; in fact, it's 0. This is the output when running the program.


The current total is 10
The current total is 10
After adding 10 two times, the total is 0

The reason is that each instance of function (f1 and f2) contains a copy of ks, and each of those instances winds up with a total value of 10, but ks is unchanged. This may or may not be what is intended, but it is important to remember that the default behavior of boost::function is to copy the function object that it is to invoke. If that produces incorrect semantics, or if the copying of some function objects is too expensive, you must wrap the function objects in boost::reference_wrapper so that boost::function's copy will be a copy of a boost::reference_wrapper, which just holds a reference to the original function object. You rarely use boost::reference_wrapper directly, but rather you use two helper functions, ref and cref. Those functions return a reference_wrapper that holds a reference or const reference to the parameterizing type. To get the semantics that we want in this case, using the same instance of keeping_state, we need to change the code, like this:


int main() {
keeping_state ks;
boost::function<int(int)> f1;
f1=boost::ref(ks);
boost::function<int(int)> f2;
f2=boost::ref(ks);
std::cout << "The current total is " << f1(10) << '\n';
std::cout << "The current total is " << f2(10) << '\n';
std::cout << "After adding 10 two times, the total is "
<< ks.total() << '\n';
}

This usage of boost::ref informs boost::function that we want to store a reference to the function object, not a copy. Running this program produces the following output:


The current total is 10
The current total is 20
After adding 10 two times, the total is 20

This is exactly the behavior that we needed in this case. The difference between using boost::ref and boost::cref is exactly the same as the difference between references and references to constyou can only call constant member functions for the latter. The following example uses a function object called something_else, which has a function call operator that is const.


class something_else {
public:
void operator()() const {
std::cout << "This works with boost::cref\n";
}
};

With this function object, we could use either boost::ref or boost::cref.


something_else s;
boost::function0<void> f1;
f1=boost::ref(s);
f1();
boost::function0<void> f2;
f2=boost::cref(s);
f2();

If we change the implementation of something_else and make the function non-const, only boost::ref will work, whereas boost::cref would produce an error at compile time.


class something_else {
public:
void operator()() {
std::cout <<
"This works only with boost::ref, or copies\n";
}
};
something_else s;
boost::function0<void> f1;
f1=boost::ref(s); // This still works
f1();
boost::function0<void> f2;
f2=boost::cref(s); // This doesn't work;
// the function call operator is not const
f2();

When a function contains a function object wrapped by boost::reference_wrapper, copy construction and assignment replicates the referencethat is, the copy of the function references the original function object.


int main() {
keeping_state ks;
boost::function<int,int> f1;
f1=boost::ref(ks);
boost::function<int,int> f2(f1);
boost::function<short,short> f3;
f3=f1;
std::cout << "The current total is " << f1(10) << '\n';
std::cout << "The current total is " << f2(10) << '\n';
std::cout << "The current total is " << f3(10) << '\n';
std::cout << "After adding 10 three times, the total is "
<< ks.total() << '\n';
}

This is equivalent to using boost::ref and assigning the function object ks to each instance of function.

The power that is wielded with the addition of state to callbacks is tremendous, and is one of the great advantages to using Boost.Function rather than function pointers.

Using Boost.Bind with Boost.Function


Things become even more interesting when we combine Boost.Function with a library that supports argument binding. Boost.Bind provides argument binding for free functions, class member functions, and class variables. This is a perfect fit for Boost.Function, where we often need this type of binding because the classes that we are working with are not themselves function objects. So, we transform them into function objects using Boost.Bind, and then we can store them for later invocation with Boost.Function. When separating graphical user interfaces (GUIs) from details on how to handle actions (events) from the user, callbacks of some sort are almost always used. If this callback mechanism is based on function pointers, it is hard to avoid severe limitations of the types that can be used with the callback, which in turn increases the risk of adding coupling between the presentation and the business logic. We can avoid this altogether by using Boost.Function, and when combined with a library that supports argument binding, we can supply the context to invocations of functions with ease. This is one of the most common uses of this libraryto separate knowledge of the business logic from the presentation layer.

This example includes a state-of-the-art tape recorder, which is defined thusly.


class tape_recorder {
public:
void play() {
std::cout << "Since my baby left me...\n";
}
void stop() {
std::cout << "OK, taking a break\n";
}
void forward() {
std::cout << "whizzz\n";
}
void rewind() {
std::cout << "zzzihw\n";
}
void record(const std::string& sound) {
std::cout << "Recorded: " << sound << '\n';
}
};

This tape recorder could be controlled from a GUI, or perhaps from a scripting client, or from any other source, which means that we don't want to couple the invocation of the functions to their implementation. A common way to create that separation is through special objects that are only responsible for executing a command, allowing the client to remain ignorant of how the command is executed. This is known as the Command pattern, and is very useful in its own right. One of the problems with the typical implementation of this pattern is the need to create separate classes to execute each command. The following snippet demonstrates how this might look:


class command_base {
public:
virtual bool enabled() const=0;
virtual void execute()=0;
virtual ~command_base() {}
};
class play_command : public command_base {
tape_recorder* p_;
public:
play_command(tape_recorder* p):p_(p) {}
bool enabled() const {
return true;
}
void execute() {
p_->play();
}
};
class stop_command : public command_base {
tape_recorder* p_;
public:
stop_command(tape_recorder* p):p_(p) {}
bool enabled() const {
return true;
}
void execute() {
p_->stop();
}
};

This is not a very attractive solution, because it leads to code bloat in the form of numerous simple command classes, all with the sole responsibility of invoking a single member function on an object. Sometimes, this can prove necessary, because the commands may need to implement business logic as well as execute a function, but it is often just a result of limitations in the tools that we are using. These command classes can be used like this:


int main() {
tape_recorder tr;
// Using the command pattern
command_base* pPlay=new play_command(&tr);
command_base* pStop=new stop_command(&tr);
// Invoked when pressing a button
pPlay->execute();
pStop->execute();
delete pPlay;
delete pStop;
}

Now, rather than creating an additional number of concrete command classes, we could generalize a bit if we take advantage of the fact that the commands we are implementing are all calling a member function with a void return, taking no argument (ignoring for the moment the function record, which does take an argument). Rather than creating a family of concrete commands, we could store a pointer to the correct member function in the class. This is a huge step in the right direction,[6] and it works like this:

[6] Albeit slightly less efficient.


class tape_recorder_command : public command_base {
void (tape_recorder::*func_)();
tape_recorder* p_;
public:
tape_recorder_command(
tape_recorder* p,
void (tape_recorder::*func)()) : p_(p),func_(func) {}
bool enabled() const {
return true;
}
void execute() {
(p_->*func_)();
}
};

This implementation of the commands is much nicer, because it relieves us from having to create separate classes that do basically the same thing. The difference here is that we are storing a pointer to a tape_recorder member function in func_, which is provided in the constructor. The execution of the command is not something you should show all your friends, because the pointer-to-member operators do have a habit of confusing people. However, this can be considered a low-level implementation detail, so that's fine. With this class, we have performed a generalization that proves useful in that we don't have to implement separate command classes anymore.


int main() {
tape_recorder tr;
// Using the improved command
command_base* pPlay=
new tape_recorder_command(&tr,&tape_recorder::play);
command_base* pStop=
new tape_recorder_command(&tr,&tape_recorder::stop);
// Invoked from a GUI, or a scripting client
pPlay->execute();
pStop->execute();
delete pPlay;
delete pStop;
}

You may not realize it, but we're actually starting to implement a simplified version of boost::function, which already does what we want. Rather than reinvent the wheel, let's focus on the task at hand: separating the invocation and the implementation. Here is a new implementation of the command class, which is a lot easier to write, maintain, and understand.


class command {
boost::function<void()> f_;
public:
command() {}
command(boost::function<void()> f):f_(f) {}
void execute() {
if (f_) {
f_();
}
}
template <typename Func> void set_function(Func f) {
f_=f;
}
bool enabled() const {
return f_;
}
};

By using Boost.Function in the implementation, we can immediately benefit from the flexibility of being compatible both with functions and function objectsincluding function objects produced by binders. The command class stores the function in a boost::function that returns void and doesn't take any arguments. To make the class more flexible, we provide a way to change the function object at runtime, using a parameterized member function, set_function.


template <typename Func> void set_function(Func f) {
f_=f;
}

By using parameterization, any function, function object, or binder is compatible with our command class. We could also have opted to have a boost:: function as argument, and achieve the same effect using the converting constructor of function. This command class is very general, and we can use it with our tape_recorder class or just about anything else. An additional advantage over the previous approach when using a base class and concrete derived classes (which in turn makes us use pointers for polymorphic behavior) is that it becomes easier to manage lifetime issueswe don't have to delete the command objects anymore, as they can be passed and saved by value. We test whether the command is enabled or not by using the function f_ in a Boolean context. If the function doesn't contain a target, a function or function object, this yields false, which means that we cannot invoke it. This is tested in the implementation of execute. Here's a sample program that uses our new class:


int main() {
tape_recorder tr;
command play(boost::bind(&tape_recorder::play,&tr));
command stop(boost::bind(&tape_recorder::stop,&tr));
command forward(boost::bind(&tape_recorder::stop,&tr));
command rewind(boost::bind(&tape_recorder::rewind,&tr));
command record;
// Invoked from some GUI control...
if (play.enabled()) {
play.execute();
}
// Invoked from some scripting client...
stop.execute();
// Some inspired songwriter has passed some lyrics
std::string s="What a beautiful morning...";
record.set_function(
boost::bind(&tape_recorder::record,&tr,s));
record.execute();
}

To create the concrete commands, we use Boost.Bind to create function objects that, when invoked through the function call operator, calls the correct member function of tape_recorder. These function objects are self-contained; they are nullary function objects, meaning that they can be directly invoked without passing any arguments, which is what a boost::function<void()> expects. In other words, the following code snippet creates a function object that invokes the member function play on the instance of tape_recorder that it is configured with.


boost::bind(&tape_recorder::play,&tr)

Normally, we wouldn't be able to store the returned function object from the call to bind, but because Boost.Function is compatible with any function object, this is possible.


boost::function<void()> f(boost::bind(&tape_recorder::play,&tr));

Notice that the class also supports calling record, which takes an argument of type const std::string&, because of the member function set_function. Because the function object must be nullary, we need to bind the context so that record still gets its argument. That, of course, is a job for binders. Thus, before calling record, we create a function object that contains the string to be recorded.


std::string s="What a beautiful morning...";
record.set_function(
boost::bind(&tape_recorder::record,&tr,s));

Executing the function object stored in record passes the string to tape_recorder::record, invoked on the tape_recorder instance tr. With Boost.Function and Boost.Bind, it is possible to achieve the decoupling that makes it possible for the invoking code to know nothing about the code being invoked. It's immensely useful to combine these two libraries in this way. Having shown you the command class, it's time for me to come clean. All you really need, because of the power of Boost.Function, is the following:


typedef boost::function<void()> command;

Using Boost.Lambda with Boost.Function


Just as Boost.Function is compatible with the function objects that are created by Boost.Bind, it also supports Boost.Lambda, which also creates function objects. Any function object that you create with the Lambda library is compatible with the corresponding boost::function. We have covered some ground on binding in the previous section, and the main difference is that it is possible to do even more with Boost.Lambda. We can create these small, unnamed functions at ease, and store them in instances of boost::function for subsequent invocation. We have covered lambda expressions in the previous chapterany of the examples that were provided there produced function objects that could be stored in an instance of function. The combination of function and libraries that create function objects is extremely powerful.

Thinking About the Cost


There's no such thing as a free lunch, as the saying goes, and this certainly applies to Boost.Function, too. There are some disadvantages of using Boost.Function compared to using function pointers, most notably the increase in size. A function pointer obviously occupies the space of one function pointer (duh!), whereas an instance of boost::function is three times as large. This can be an issue when there is a very large number of callbacks. Function pointers are also slightly more efficient when invoked, because where a function pointer is invoked directly, Boost.Function may require two calls through function pointers. Finally, there may be cases where the backward compatibility with C libraries makes function pointers the only choice.

Although these are potential disadvantages of Boost.Function, it is not very often that these are real-world issues. The extra size is still very small, and the overheard of the (potential) extra call through a function pointer usually comes at a very small cost indeed compared to the time it takes to actually perform the computations of the target function. It should be the rare situation that mandates using function instead of Boost.Function. The great advantages and the flexibility that is gained through using the library easily outweigh these costs.

Under the Hood


As always, it is valuable to understand at least the basics of how a library works. We shall consider the three cases of storing and invoking a function pointer, a pointer to member function, and a function object. These three are all different. To see exactly how Boost.Function works, just look at the source codewe are going to do things a bit differently, in an attempt to clearly show how different versions of such beasts demand slightly different approaches. We will also have a class with different requirements, namely that when calling a member function, a pointer to an instance of the class must be passed to the constructor of function1 (which is the name of our class). function1 supports functions taking exactly one argument. A relaxation of the requirements compared to Boost.Function is that even for member functions, only the type of the result and the argument need to be supplied. This is a direct consequence of the requirement that the constructor must be passed a pointer to an instance of the class for which the member is to be called (the type is automatically deduced).

The approach we shall take is to create a parameterized base class that declares a virtual function for the function call operator; then, three classes are derived from this base class for the different forms of function invocations that we are to support. These classes take care of all the work, while another, function1, decides which of these concrete classes to instantiate depending on the arguments to the constructor. Here is the base class for the invokers, invoker_base.


template <typename R, typename Arg> class invoker_base {
public:
virtual R operator()(Arg arg)=0;
};

Next, we begin with the definition of function_ptr_invoker, which is a concrete invoker that derives publicly from invoker_base. Its purpose is to invoke free functions. The class also accepts two types, the return type and the argument type, and these are used for the constructor, which takes a function pointer as argument.


template <typename R, typename Arg> class function_ptr_invoker
: public invoker_base<R,Arg> {
R (*func_)(Arg);
public:
function_ptr_invoker(R (*func)(Arg)):func_(func) {}
R operator()(Arg arg) {
return (func_)(arg);
}
};

This class template can be used to call any free function that accepts one argument. The function call operator simply invokes the function stored in func_ with the parameter it is given. Note the (admittedly strange) line that declares a variable to store the function pointer.


R (*func_)(Arg);

You can make that a little plainer using a typedef.


typedef R (*FunctionT)(Arg);
FunctionT func_;

Next, we need a class template that can handle member function calls. Remember that it should also require a pointer to an instance of the class type when constructed, which is different from the way that Boost.Function works. It does save us some typing, because the compiler, not the programmer, deduces the type of the class.


template <typename R, typename Arg, typename T>
class member_ptr_invoker :
public invoker_base<R,Arg> {
R (T::*func_)(Arg);
T* t_;
public:
member_ptr_invoker(R (T::*func)(Arg),T* t)
:func_(func),t_(t) {}
R operator()(Arg arg) {
return (t_->*func_)(arg);
}
};

This class template is very similar to the version for free function pointers. It differs from the previous one in that the constructor stores a member function pointer and a pointer to an object and the function call operator invokes the member function (func_) on that object (t_).

Finally, we need a version that is compatible with function objects. This is actually the easiest implementation of all, at least when defining it our way. By using a single template parameter, we just state that the type T must indeed be a function object, because we intend to invoke it as such. Enough said.


template <typename R, typename Arg, typename T>
class function_object_invoker :
public invoker_base<R,Arg> {
T t_;
public:
function_object_invoker(T t):t_(t) {}
R operator()(Arg arg) {
return t_(arg);
}
};

Now that we have these building blocks in place, all that remains is to put the pieces together in our version of boost::function, the function1 class. We want a way to detect which kind of invoker to instantiate. We can then save it in a pointer to invoker_base. The trick here is to provide constructors that are capable of detecting which type of invoker is correct for the supplied arguments. It's just overloading, with a little twist involving parameterizing two of the constructors.


template <typename R, typename Arg> class function1 {
invoker_base<R,Arg>* invoker_;
public:
function1(R (*func)(Arg)) :
invoker_(new function_ptr_invoker<R,Arg>(func)) {}
template <typename T> function1(R (T::*func)(Arg),T* p) :
invoker_(new member_ptr_invoker<R,Arg,T>(func,p)) {}
template <typename T> function1(T t) :
invoker_(new function_object_invoker<R,Arg,T>(t)) {}
R operator()(Arg arg) {
return (*invoker_)(arg);
}
~function1() {
delete invoker_;
}
};

As you can see, the hard part here is to correctly define the deduction system that is needed in order to support function pointers, class member functions, and function objects. This is true regardless of the actual design that is used to implement a library with this kind of functionality. To conclude, here is some sample code that we can use to test the solution.


bool some_function(const std::string& s) {
std::cout << s << " This is really neat\n";
return true;
}
class some_class {
public:
bool some_function(const std::string& s) {
std::cout << s << " This is also quite nice\n";
return true;
}
};
class some_function_object {
public:
bool operator()(const std::string& s) {
std::cout << s <<
" This should work, too, in a flexible solution\n";
return true;
}
};
All of these are acceptable for our function1 class:
int main() {
function1<bool,const std::string&> f1(&some_function);
f1(std::string("Hello"));
some_class s;
function1<bool,const std::string&>
f2(&some_class::some_function,&s);
f2(std::string("Hello"));
function1<bool,const std::string&>
f3(boost::bind(&some_class::some_function,&s,_1));
f3(std::string("Hello"));
some_function_object fso;
function1<bool,const std::string&>
f4(fso);
f4(std::string("Hello"));
}

It also works with function objects returned from binder libraries, such as Boost.Bind and Boost.Lambda. Our class is a lot more simplistic than the ones found in Boost.Function, but it should be sufficiently detailed to see the problems and the solutions involved when creating and using such a library. To know a little something about how a library is implemented is helpful for using it as effectively as possible.

/ 124