C++ Functor -- A Callback and Event Library


Overview

C++ Functor is a bunch of very handy classes to store arbitrary functor objects in one single interface. This includes functionpointer, methodpointer and functor classes (classes that overload operator()). This works via polymorphism, so it's not extremely fast, though. But, in comparison to QTs event system, for example, it's far faster, more easy to debug and maintain. Wrong usage will be handled by the compiler. It's typesafe and kinda scalable. Currently the stored functions may have up to 7 parameter of arbitrary type.

Links

The sourceforge project page is located here.
You can download the latest version here.
The doxygen source documentation is here.

Usage

Single Events

In the most common case you'll use the C++ functor via the event class. You'll instantiate the template class like this:
  #include "event.h"
  event<void, int, const std::string> my_event;
   
This will create an event that holds a functor with returntype void and two arguments: an int and a const std::string.
You can assign a value (functor) to it like this:
  #include "mkfunc.h"
  void foo( int, const std::string );
  /* ... */
  my_event.assign( mkFunctor<void, int, const std::string>::create( foo ) );
    
Now my_event is associated with foo. To call the associated function, you use the emit method:
  my_event.emit( 10, "Hello World\n" );
    
You should use is_null() to check if a functor is assigned, each time before you call emit.

Event Lists

This was the standard-case (right now I'm consider declaring event deprecated and forcing users to use event_list). But there are far better ways using the functor classes. For example, the client might want to add several functions to the same event. For this purpose, there is event_list:
  #include "event_list.h"
  typedef event_list<void,int,const std::string> my_event_list_t;
  my_event_list_t my_event_list;
  my_event_list.append( mkFunctor<void, int, const std::string>::create( foo ) );
  my_event_list.emit_all( 10, "Hello World\n" );
    
This has an enormous advantage: If the list of functors is empty, none will be called. In contrast to event<>::emit (which will throw an exception, if no functor is assigned), this is a far more convenient handling. Since every function has a returntype, we want to be able to access each functions result. We do this with a std::list (that's default behaviour. You can use any (stdc++lib or hand-made) list/vector class, as you will see later in this chapter). Here's an example:
  my_event_list_t::return_list rl;
  my_event_list.emit_all( 10, "Hello World\n", rl );
  for( my_event_list_t::iterator i = rl.begin(); i != rl.end(); i++ )
  std::cout << *i;
    
You can use custom_event_list to specify another type of list or vector that is used for the return types like this:
  #include "event_list.h"
  typedef custom_event_list<std::list, std::vector, int, int> my_cel_t;
    // the first argument is the list-type that holds the functors, the second type holds the return values
  my_cel_t my_cel;
  typedef mkFunctor<int, int> mkfunc;
  my_cel.append( mkfunc::create( foo ) );
  my_cel.append( mkfunc::create( bar ) );
  my_cel_t::return_list rl; // rl will be a std::vector
  my_cel.emit_all( 10, rl );
    // my_cel_t::iterator is typedef'ed to std::vector<int>::iterator
  for( my_cel_t::iterator i = my_cel.begin(); i != my_cel.end(); i++ )
    std::cout << *i;
    

Different Functor Types

As stated above, you can use functionpointer, methodpointer and functor objects with the C++ Functor classes. It's really quite easy:
  #include "event.h"
  #include "mkfunc.h"
  #include <iostream>

  int function(int i) {
    return i*2;
  }
  struct test {
    int method(int i) {
      return i/2;
    }
  };
  struct functor {
    int operator()(int i) {
      return i+1;
    };
  }
  /* ... */
  test t;
  functor f;
  event<int,int> my_event;
  my_event.assign( mkFunctor<int, int>::create(function) );
  int a = my_event.emit( 10 );
  my_event.assign( mkFunctor<int, int>::create( &t, &test::method ) );
  int b = my_event.emit( 20 );
  my_event.assign( mkFunctor<int, int>::create(f) );
  int c = my_event.emit( 30 );

  std::cout << "a: " << a << ", b: " << b << ", c: " << c << '\n';
    
This program will print
  a: 20, b: 10, c: 31
    

Notes

Since C++ Functor is a pure template library, no linkage needs to be done, because everything is inlined.

/* ... */
      Copyright (c) 2003 - 2004 Daniel Albuschat, daniel at viming.de