views:

274

answers:

4

Consider a following code:

struct X {
  void MethodX() {
    ...
  }
};

struct Y {
  void MethodY() {
    ...
  }
};

void test () {
  X x;
  Y y;
  Dispatcher d;
  d.Register("x", x, &X::MethodX);
  d.Register("y", y, &Y::MethodY);
  d.Call("x");
  d.Call("y");
}

The question is how to implement Dispatcher. I don't mind X and Y may inheriting from something, but Dispatcher should allow further clients (not only X and Y). And I would like to avoid void* pointers if possible :)

+5  A: 

Take a look at boost::function, it does this.

Assaf Lavie
I doesn't solve the problem. Take a look at the updated question.
Łukasz Lew
Maybe it does. I'm investigating :)
Łukasz Lew
+1  A: 

I have a similar answer here, but Mykola's answer is closer to what you need.

Dave Van den Eynde
+1  A: 

Take a look at this paper:

http://www.oopweb.com/CPP/Documents/FunctionPointers/Volume/CCPP/functor/functor.html

It implements a template based functor in C++. void* is used under the hoods, but it's all type-safe because it's wrapped by template functions that create and unwrap the void*. It would make implementing this easy. It support a variety of call styles that plain method pointers don't (e.g. you can pass a function returning something as a functor returning void and it automatically ignores the return value)

Lou Franco
+2  A: 

To avoid boost usage and implement your own you can take a look at the book http://en.wikipedia.org/wiki/Modern_C%2B%2B_Design

There is a Loki library described in the book with a good explanation how to make your own smart enough for your need functor.

class Dispather
{
public:
    typedef boost::function< void ( void ) > FunctionT;

    void Register( const std::string& name, FunctionT function )
    {
        registered_[ name ] = function;
    }

    void Call( const std::string& name )
    {
        RegisterdFunctionsT::const_iterator it =
            registered_.find( name );

        if ( it == registered_.end() )
            throw std::logic_error( "Function is not registered" );

        (it->second)();
    }

private:
    typedef std::map< std::string, FunctionT > RegisterdFunctionsT;
    RegisterdFunctionsT registered_;

};

int main()
{
    X x;
    Y y;

    Dispather d;
    d.Register( "x", boost::bind( &X::MethodX, &x ) );
    d.Register( "y", boost::bind( &Y::MethodY, &y ) );

    d.Call( "x" );
    d.Call( "y" );

    return 0;
}
Mykola Golubyev
Łukasz Lew
To avoid boost usage ... and then you're using boost::function?
Dave Van den Eynde