Topic : Callbacks
Author : Unknown
Page : 1

Callbacks


One of the most vexing problems facing C++ programmers is the that of passing a function to a function. In computer science lingo, the function passed as an argument is called a callback, since it is "called back" by the other function. For example, suppose you have a function that finds the minimum of another function:

void Minimize( double (*f)( double), double initial_x,
               double &x_at_minimum, double &minimum_f);


Here, the function to be minimized is f, the initial guess of the independent variable is initial_x, while the answers are given in x_at_minimum and minimum_f. This works fine so far, but what if the function that you want to minimize is a member function of a class? In that case, you cannot use the minimizer described above. So, now, you might write another minimizer that does the same thing but to a different type of function; you can even use templates to make it generic to all classes.

template< class Class, class Sub_Class>
void Minimize( Sub_Class &object, double (Class::*f)( double), double initial_x,
               double &x_at_minimum, double &minimum_f);


Since we are dealing with a function that is now bound to a particular object object, we must let the minimizer function know about that object. Also, object may belong to a sub-class of the class Class, so we allow for that in the template arguments. But that isn't all. We also must allow for const member functions, so we need a third function:

template< class Class, class Sub_Class>
void Minimize( const Sub_Class &object, double (Class::*f)( double) const, double initial_x,
               double &x_at_minimum, double &minimum_f);


We now have all of our possibilities covered, but we have to write three minimizer functions instead of one. Most vexing of all, if we use only function pointers, the functions all must be written from scratch; it isn't possible to have all three functions call one common function containing the guts of the minimizer. But thanks to a very nice class library by Rich Hickey, it is now possible to wrap these different types of functions into one common object called a functor, and then use the functor as an argument to one minimizer function.

Functors

A functor is nothing more than an object that behaves like a function. In C++, you can give an object the syntax of a function call:
My_Functor f;

double x, y;
x = ...;

y = f(x);



Rich Hickey's accomplishment is a templated library of functors that can wrap ordinary C++ functions. Suppose we have a set of functions that take one double argument and return a double value. Here is how we would wrap them using Hickey's library:

double f( double);

class Thing{

public:
  double f( double);
  
  double g( double) const;
};

class New_Thing: public Thing{
...
};

New_Thing thing1, thing2;

Functor1wRet< double, double> functor1, functor2, functor3;

functor1 = makeFunctor( f);
functor2 = makeFunctor( thing1, Thing::f);
functor3 = makeFunctor( thing2, Thing::g);



The first template argument represents the argument's type, and the last template argument represents the return type. Other functor classes are included for cases of no return values and different numbers of arguments.
So now, here is how we would write our minimizer:


//########################################
void Minimize( const Functor1wRet< double, double> f, double initial_x,
               double &x_at_minimum, double &minimum_f){

  // Guts of minimizer go here
  ...
}

//########################################
void Minimize( double (*f)( double), double initial_x,
               double &x_at_minimum, double &minimum_f){

  Minimize( makeFunctor( f), initial_x, x_at_minimum, minimum_f);
}

//########################################
template< class Class, class Sub_Class>
void Minimize( Sub_Class &object, double (Class::*f)( double), double initial_x,
               double &x_at_minimum, double &minimum_f){

  Minimize( makeFunctor( object, f), initial_x, x_at_minimum, minimum_f);
}

//########################################
template< class Class, class Sub_Class>
void Minimize( const Sub_Class &object, double (Class::*f)( double) const, double initial_x,
               double &x_at_minimum, double &minimum_f){

  Minimize( makeFunctor( object, f), initial_x, x_at_minimum, minimum_f);
}



So, we put our minimizer's guts into one function, and write three very short functions that call the main function. In OOMPAA, there are many functions that take other functions as arguments; this is the approach that I use for all of them.
Finally, I should note that I wasn't actually able to use Rich Hickey's code. He does some low-level bit-twiddling that is perfectly legal and portable, but the optimizer on the Kuck and Associates compiler causes wrong answers to be generated at run-time. So I wrote my own callback library that has mostly the same functionality and uses his ideas, but implements things a bit differently. It resides in the oompaa namespace, inside the Oompaa namespace.


Page : 1