Reputation: 279
I'm still trying to get the swing of metaprogramming, and I'm stumped.
What's I'd like to do is create a class/struct/whatever, supply it a std::tuple and have it automatically generate member functions based on the object types in the tuple. The goal is to have classes derive from MessageHandler
e.g.
typedef std::tuple< MessageA, MessageB, MessageC > MessageSet;
template< class T >
class MessageHandler
{
// some magic metaprogramming would "create"...
virtual void processMsg( const MessageA& ) = 0;
virtual void processMsg( const MessageB& ) = 0;
virtual void processMsg( const MessageC& ) = 0;
};
I've read that you can't have virtual functions in templates, but I didn't know if that was still true for C++11.
Thanks.
Upvotes: 3
Views: 437
Reputation: 59811
You don't need tuple to do that:
struct MessageA{};struct MessageB{};struct MessageC{};
template <typename T>
struct message_interface {
virtual void processMessage(const T& t) = 0;
};
template< typename... Args >
struct message_handler : public message_interface<Args>...
{};
struct message_impl : message_handler<MessageA, MessageB, MessageC>
{
void processMessage(const MessageA&){}
void processMessage(const MessageB&){}
void processMessage(const MessageC&){}
};
int main()
{
message_impl i;
return 0;
}
It would probably be a good idea to check if the argument list is unique and static assert on that. Also make sure it does not contain reference types or other undesirables. Those will usually end up as errors when you try to form the argument type but it will safe your users some trouble.
EDIT: If you absolutely require to support tuple
add a specialization:
template< typename... Args >
struct message_handler< std::tuple<Args...> > : public message_interface<Args>...
{};
Upvotes: 4
Reputation: 361254
The answer is variadic template, partial specialization, and inheritance as:
//primary template!
template<typename T>
class MessageHandler;
//variadic template, partial specialization and inheritance!
template<typename H, typename ...T>
class MessageHandler<std::tuple<H,T...>> : public MessageHandler<std::tuple<T...>>
{
virtual void processMsg( const H& ) = 0;
};
template<typename T>
class MessageHandler<std::tuple<T>>
{
virtual void processMsg( const T& ) = 0;
};
Upvotes: 5