views:

812

answers:

2

I have a callback mechanism, the classes involved are:

class App
{
    void onEvent(const MyEvent& event);
    void onEvent(const MyOtherEvent& event);

    Connector connect;
}

class Connector
{  
   template <class T> void Subscribe(boost::function <void (const T&)> callback);
}

App::App()
{
    connect.Subscribe<MyEvent>(&App::OnEvent<MyEvent>);
}

First off this code doesn't compile, it's an illustration.

The use of templates complicates my example, but I left them in because its affecting my problem. It seems certain to me that my subscribe needs to be templated because the Connector class doesn't know how many event types it handles. When I try to create a:

boost::function f = &App::OnEvent,

I tried creating OnEvent as a template function, with specializations, but it seems that the compiler is treating my OnEvent functions as overloads rather than template specializations, or else I get the template specialization not in namespace error if I try to explicitly declare it as

template <> OnEvent(const MyEvent& e) ...

I can get the following to compile:

boost::function <void (App*, const MyEvent&)> f = &App::OnEvent;
f(this, e);

That compiles, runs, and works.

boost::function<void (const MyEvent&)> g = boost::bind(&App::OnEvent, this);

does not. I think its because I'm not correctly specifying the address of an overloaded function.

Having now explained all this to the teddy bear - I think that my question is "How do I correctly create a function pointer to an overloaded or templated member function and bind the this pointer to it?"

+3  A: 

You are going to want to do

boost::function<void (const MyEvent&)> g = boost::bind(&App::OnEvent, this, _1);

You should be able to do g(event); with that

I am not quite sure what you are trying to accomplish here, but that should solve one of your problems for now.

Charles
swarfrat
That code will make g(event) work, but it will not exactly work with templates like I think you want.If you are trying to do what I think you are trying to do you might be better off forgetting that template and use an event interface declaration instead. I would be interested to see how boost::function would work with a templated function definition, but I do not think that is possible.You might want to check out Boost::Fusion and the Interpreter example in the lib directory. It is the most advanced Boost::function implementer I know of. libs/function_types/example/interpreter.hpp
Charles
I removed the templates from the OnEvent side (subscribe is still templated), and it works for one event. But as soon as I overload OnEvent, it can no longer deduce which one. I can see why, as the function pointer knows its type, but boost::bind does not.
swarfrat
+4  A: 

I think you need to disambiguate the address of the overloaded function. You can do this by explicitly casting the function pointer to the one with the correct parameters.

boost::bind( static_cast<void (App::*)( MyEvent& )>(&App::OnEvent) , this, _1);

Similar problem + solution on gamedev.net

christopher_f
good info, very neat
Charles
It's a shame you can only have one accepted answer, but this was the piece I was missing. Thanks for the link.
swarfrat