If you really do not want to use virtual functions (for them this is really an ideal use case, but I do not know about your message classes), you can use CRTP :
template <typename U> struct Consumer { template <typename T> void callback(T msg) { static_cast<U*>(this)->callback(msg); } }; struct Client : Consumer<Client> { void callback(Msg1 msg); void callback(Msg2 msg); void callback(Msg3 msg); };
The problem, of course, is that you can no longer store Consumer objects in a container. Since all compilation time, the actual client type must be stored next to the consumer object so that the compiler can call the correct callback function. Virtual functions allow you to wait until that time ...
Is there a reason not to have Msg polymorphic classes and use standard virtual functions (except "I have to rewrite all the code, but I can not")?
EDIT If your problem is with message classes, why not use something similar, assuming message classes implement the DoSomething member function: (this method is known as Type Erasure)
struct AnyMsg { template <typename Msg> AnyMsg(Msg x) : impl(newImpl(x)) {} void DoSomething() { impl->DoSomething(); } private: struct Impl { virtual ~Impl() {} virtual void DoSomething() = 0; };
You can customize the behavior of newImpl to get what you want (for example, default actions if the message class does not have a DoSomething member class function, specialization for some message classes, or something else). Thus, you implement the Msg classes, as it would with your solution for templates, and you have a unique facade that you can pass to virtual functions in your client classes.
If the message classes will be very different, and the client classes may respond differently to them, and you will have many message classes, it starts to smell. Or perhaps you have a candidate for an ugly and scary visitor template .