Reputation: 279
As you can see in the code below, I'm trying to mock up a callback structure supplying std::tuple<>
of messages into a factory. My issue is that it looks like the compiler isn't reducing the "return type" of (for example) std::tuple_element< 2, MessageOne, MessageTwo, MessageTen >
to just MessageTwo
-- which is confusing the linkage. See below.
#include <map>
#include <tuple>
//----------------------------------------------------------------------
//
class MessageBase
{
public:
MessageBase( const int _id ) : m_id( _id ) { }
virtual int getMessageID() const = 0;
private:
const int m_id;
};
#define MESSAGE( NAME, VAL ) \
class Message##NAME : public MessageBase { \
public: \
Message##NAME() : MessageBase( VAL ) { } \
virtual int getMessageID() const { return ( VAL ); } \
}
MESSAGE( One, 1 );
MESSAGE( Two, 2 );
MESSAGE( Ten, 10 );
class StaticMessageHandlerInterface
{
public:
virtual void processMsg( const MessageOne& ) { }
virtual void processMsg( const MessageTwo& ) { }
virtual void processMsg( const MessageTen& ) { }
};
//----------------------------------------------------------------------
//
class MessageCallbackInterface
{
public:
virtual void receiveMsg( const MessageBase* ) = 0;
};
template< class MessageT, class HandlerT >
class MessageCallbackHandler : public MessageCallbackInterface
{
public:
MessageCallbackHandler( HandlerT& _handler )
: r_handler( _handler )
{ }
void receiveMsg( const MessageBase* _msg )
{
const MessageT* msg( ( const MessageT* )(_msg) );
r_handler.processMsg( *msg );
}
private:
HandlerT& r_handler;
}; // MessageCallbackHandler
//----------------------------------------------------------------------
//
template< typename TupleT >
class MessageFactory
{
public:
MessageFactory()
: p_handler( nullptr )
{
init( TupleT() );
}
private:
StaticMessageHandlerInterface* p_handler;
typedef std::map< int, MessageCallbackInterface* > MessageCallbackMap;
MessageCallbackMap m_callbackMap;
template< std::size_t I = 0, typename ... T >
inline typename std::enable_if< I < sizeof ... (T), void >::type
init( const std::tuple< T... >& t )
{
const auto& msg( std::get<I>( t ) );
m_callbackMap[ msg.getMessageID() ] =
new MessageCallbackHandler <
std::tuple_element< I, std::tuple< T ... > >,
StaticMessageHandlerInterface
> ( *p_handler ) ;
init< I + 1, T... >( t );
}
template< std::size_t I = 0, typename ... T >
inline typename std::enable_if< I == sizeof... (T), void >::type
init( const std::tuple< T... >& ) { }
};
//----------------------------------------------------------------------
//
int
main( const int, const char** )
{
typedef std::tuple< MessageOne, MessageTwo, MessageTen > Foople;
typedef MessageFactory< Foople > FoopleFactory;
FoopleFactory factory;
}
from which, GCC complains...
test.C: In instantiation of 'void MessageCallbackHandler(MessageT, HandlerT)::receiveMsg(const MessageBase*) [with MessageT = std::tuple_element(2u, std::tuple(MessageOne, MessageTwo, MessageTen) ); HandlerT = StaticMessageHandlerInterface]': test.C:143:5:
required from here test.C:83:11: error: no matching function for call to 'StaticMessageHandlerInterface::processMsg(const std::tuple_element(2u, std::tuple(MessageOne, MessageTwo, MessageTen) )&)' r_handler.processMsg( *msg ); ^ test.C:83:11: note: candidates are: test.C:57:22: note: virtual void StaticMessageHandlerInterface::processMsg(const MessageOne&) virtual void processMsg( const MessageOne& ) { } ^ test.C:57:22: note: no known conversion for argument 1 from 'const std::tuple_element(2u, std::tuple(MessageOne, MessageTwo, MessageTen) )' to 'const MessageOne&' test.C:58:22: note: virtual void StaticMessageHandlerInterface::processMsg(const MessageTwo&) virtual void processMsg( const MessageTwo& ) { } ^ test.C:58:22: note: no known conversion for argument 1 from 'const std::tuple_element(2u, std::tuple(MessageOne, MessageTwo, MessageTen) )' to 'const MessageTwo&' test.C:59:22: note: virtual void StaticMessageHandlerInterface::processMsg(const MessageTen&) virtual void processMsg( const MessageTen& ) { } ^ test.C:60:22: note: no known conversion for argument 1 from 'const std::tuple_element(2u, std::tuple(MessageOne, MessageTwo, MessageTen) )' to 'const MessageTen&'
(Sorry for the Markdown butchering. May be easier just to compile it.)
Upvotes: 1
Views: 899
Reputation: 44181
You need to access the inner typedef to get the actual element type. Right now you're passing in the std::tuple_element
type.
m_callbackMap[ msg.getMessageID() ] =
new MessageCallbackHandler <
typename std::tuple_element< I, std::tuple< T ... > >::type,
StaticMessageHandlerInterface
> ( *p_handler ) ;
Upvotes: 1