RMHarris157
RMHarris157

Reputation: 279

std::tuple to member functions

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

Answers (2)

pmr
pmr

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

Sarfaraz Nawaz
Sarfaraz Nawaz

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

Related Questions