This makes no sense to me. GCC is complaining that the call below in main()
to processMsg()
is ambiguous, even though all of the template-created processMsg()
calls are reported back as candidates. I've tried implementing this variadic template prototype three different ways and they all lead back to this same issue of ambiguous request. I did get closer when I broke the template implementation up into different cases for and but then I could the compiler could only resolve the first lookup in the tuple.
I've pasted a small example. I'm sure I'm missing something simple....
#include <tuple>
//----------------------------------------------------------------------
//
class MessageBase
{
public:
MessageBase( const int _id ) : m_id( _id ) {}
virtual int getMessageID() const { return( m_id ); }
private:
const int m_id;
};
#define MESSAGE( NAME, VAL ) \
class Message##NAME : public MessageBase { \
public: \
Message##NAME() : MessageBase( VAL ) { } \
};
MESSAGE( One, 1 );
MESSAGE( Two, 2 );
MESSAGE( Ten, 10 );
//----------------------------------------------------------------------
//
template< typename T >
struct MyMessageInterface {
virtual void processMsg( const T& t ) { }
};
template< typename... T >
struct MyMessageHandler : public MyMessageInterface< T >...
{};
template< typename... T >
struct MyMessageHandler< std::tuple< T... > >
: public MyMessageInterface< T >...
{};
//----------------------------------------------------------------------
//
typedef std::tuple< MessageOne, MessageTwo, MessageTen > Foople;
int main()
{
MyMessageHandler< Foople > mmh;
mmh.processMsg( MessageOne() );
}
You could add a forwarder to the specialization of MyMessageHandler
:
template< typename... T >
struct MyMessageHandler< std::tuple< T... > >
: public MyMessageInterface< T >...
{
template< typename U >
void processMsg( const U& u )
{
MyMessageInterface< U >::processMsg( u );
}
};
Live example
The reason you need to do something like this (or what Jarod42 proposed) is that the virtual methods of the base classes are not visible from the derived class when the name is ambiguous. Normally you'd add a using declaration to pull in what you need, but in your case a forwarder might be easier.
You may rewrite MyMessageHandler
as follow: Live example
template <typename... Ts> struct MyMessageHandler;
template <typename T> struct MyMessageHandler<T>
{
virtual void processMsg(const T&) { }
};
template <typename T, typename...Ts>
struct MyMessageHandler<T, Ts...> : MyMessageHandler<T>, MyMessageHandler<Ts...>
{
using MyMessageHandler<T>::processMsg;
using MyMessageHandler<Ts...>::processMsg;
};
template <typename... Ts>
struct MyMessageHandler<std::tuple<Ts...>> : public MyMessageHandler<Ts...>
{
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With