来自可变模板的模糊成员请求

Ambigous member request from variadic template

本文关键字:模糊 成员 请求      更新时间:2023-10-16

这对我来说毫无意义。GCC抱怨下面main()processMsg()的调用是不明确的,尽管所有模板创建的processMsg()调用都被报告为候选。我已经尝试实现这个可变模板原型三种不同的方式,他们都导致回到这个问题的模糊请求。当我将模板实现分解为不同的情况时,我确实更接近了,但随后我可以编译器只能解析元组中的第一次查找。

我粘贴了一个小例子。我肯定我错过了一些简单的....

#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() );
}

您可以在MyMessageHandler的专门化中添加转送代理:

template< typename... T > 
struct MyMessageHandler< std::tuple< T... > > 
  : public MyMessageInterface< T >...
{
    template< typename U >
    void processMsg( const U& u )
    {
        MyMessageInterface< U >::processMsg( u );
    }
};
<<p> 生活例子/strong>

您需要这样做(或Jarod42所建议的)的原因是,当基类的名称有歧义时,基类的虚方法在派生类中是不可见的。通常情况下,你会添加一个using声明来拉入你需要的东西,但在你的情况下,一个forwarder可能更容易。

您可以这样重写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...>
{
};

您必须(不幸地)明确地消除要调用的基类的歧义:

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;
}

问题是成员查找是模糊的,因为所有的MyMessageInterface<T>都是MyMessageHandler的直接基类。

我们需要把名字集合拉到MyMessageHandler本身,这样我们就可以用这些名字组成重载集合。

第一种方法可能是这样做:using TMessageInterface<T>::processMsg;...,但当然这是不合法的。

我的建议是要么做@Jarod42所做的递归拉入processMsg函数,或者你可以做:

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

调用特定的基类' processMsg .