Ambiguous participant request from a variation template

That makes no sense to me. GCC complains that the call below main()to is processMsg()ambiguous, although all template-generated calls are processMsg()reported as candidates. I tried to implement this prototype of the variational pattern in three different ways, and they all returned to the same ambiguous query problem. I came closer when I violated the implementation of the template in different cases, but then the compiler was able to allow only the first search in the tuple.

I inserted a small example. I am sure that I am 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() );
}
+4
source share
4 answers

MyMessageHandler:

template< typename... T > 
struct MyMessageHandler< std::tuple< T... > > 
  : public MyMessageInterface< T >...
{
    template< typename U >
    void processMsg( const U& u )
    {
        MyMessageInterface< U >::processMsg( u );
    }
};

, - ( Jarod42), , , . , , , .

+4

MyMessageHandler :

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...>
{
};
+4

( ) disambigateate , :

int main()
{
    MyMessageHandler< Foople > mmh;
    mmh.MyMessageInterface<MessageOne>::processMsg( MessageOne() );
    return 0;
}

, :

template <typename Handler, typename Message>
void caller(Handler &h, const Message &m)
{
    h.MyMessageInterface<Message>::processMsg( m );
}

int main()
{
    MyMessageHandler< Foople > mmh;
    caller(mmh, MessageOne());
    return 0;
}
+1

, , MyMessageInterface<T> MyMessageHandler.

We need to insert a set of names in MyMessageHandler so that we can form a set of overloads with these names.

The first approach may be to do something like: using TMessageInterface<T>::processMsg;...but, of course, this is not legal.

My suggestion was to do what @ Jarod42 did to invoke functions recursively processMsg, or you can do:

template <typename... Ts>
struct MyMessageHandler : MyMessageInterface<Ts>... {

  template <typename Msg>
  void processMsg(const Msg &msg) {
    MyMessageInterface<Msg>::processMsg(msg);
  }

};

which calls a specific base class processMsg.

0
source

Source: https://habr.com/ru/post/1547832/


All Articles