C++ 来自可变模板的模棱两可成员请求

C++ 来自可变模板的模棱两可成员请求,c++,templates,c++11,variadic-templates,C++,Templates,C++11,Variadic Templates,这对我来说毫无意义。GCC抱怨下面在main()中对processMsg()的调用是不明确的,即使创建的所有模板processMsg()调用都被报告为候选调用。我尝试了三种不同的方法来实现这个可变模板原型,它们都会导致相同的请求不明确问题。当我将模板实现分解为不同的情况时,我确实更接近了,但是我发现编译器只能解析元组中的第一个查找 我贴了一个小例子。我肯定我错过了一些简单的东西 #include <tuple> //---------------------------------

这对我来说毫无意义。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() );
}
#包括
//----------------------------------------------------------------------
//
类消息库
{
公众:
MessageBase(const int_id):m_id(_id){}
虚拟int getMessageID()常量{return(m_id);}
私人:
const int m_id;
};
#定义消息(名称、VAL)\
类消息##名称:public MessageBase{\
公众:\
Message##NAME():MessageBase(VAL){}\
};
信息(一,1);
信息(二,二);
信息(十,十);
//----------------------------------------------------------------------
//
模板
结构MyMessageInterface{
虚空进程msg(const T&T){}
};
模板<类型名。。。T>
结构MyMessageHandler:公共MyMessageInterface。。。
{};
模板<类型名。。。T>
结构MyMessageHandler>
:public MyMessageInterface。。。
{};
//----------------------------------------------------------------------
//
typedef std::tupleFoople;
int main()
{
MyMessageHandlermmh;
processMsg(MessageOne());
}
不幸的是,您必须明确地消除要调用的基类的歧义:

int main()
{
    MyMessageHandler< Foople > mmh;
    mmh.MyMessageInterface<MessageOne>::processMsg( MessageOne() );
    return 0;
}
intmain()
{
MyMessageHandlermmh;
MyMessageInterface::processMsg(MessageOne());
返回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;
}
模板
无效调用方(处理程序&h、常量消息&m)
{
h、 MyMessageInterface::processMsg(m);
}
int main()
{
MyMessageHandlermmh;
调用者(mmh,MessageOne());
返回0;
}

您可以按如下方式重写
MyMessageHandler

模板结构MyMessageHandler;
模板结构MyMessageHandler
{
虚空进程msg(常数T&){}
};
模板
结构MyMessageHandler:MyMessageHandler,MyMessageHandler
{
使用MyMessageHandler::processMsg;
使用MyMessageHandler::processMsg;
};
模板
结构MyMessageHandler:公共MyMessageHandler
{
};

您可以将转发器添加到
MyMessageHandler
的专门化中:

template< typename... T > 
struct MyMessageHandler< std::tuple< T... > > 
  : public MyMessageInterface< T >...
{
    template< typename U >
    void processMsg( const U& u )
    {
        MyMessageInterface< U >::processMsg( u );
    }
};
模板
结构MyMessageHandler>
:public MyMessageInterface。。。
{
模板
void processMsg(常量U&U)
{
MyMessageInterface::processMsg(U);
}
};


需要这样做的原因(或Jarod42建议的)是,当名称不明确时,基类的虚拟方法在派生类中不可见。通常,您会添加一个using声明来获取所需内容,但在您的情况下,转发器可能更容易。

问题在于成员查找不明确,因为所有
MyMessageInterface
都是
MyMessageHandler
的直接基类

我们需要将名称集拉入MyMessageHandler本身,以便可以使用这些名称形成重载集

第一种方法可能是这样做:
使用TMessageInterface::processMsg
我的建议是要么像@Jarod42那样递归地拉入
processMsg
函数,要么您可以:

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

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

};
模板
结构MyMessageHandler:MyMessageInterface。。。{
模板
无效处理消息(常量消息和消息){
MyMessageInterface::processMsg(msg);
}
};

它调用特定的基类“
processMsg

最好将模板方法直接放在类中:
template struct MyMessageHandler:public MyMessageInterface。。。{template void processMsg(const T2&t){MyMessageInterface::processMsg(t);}()解释一下为什么这会解决它,这将有助于理解它。嗯。。。因此,计划是(下一步)从上面派生一个具体的MessageHandler对象,并在派生类中重载processMsg()调用。我猜这样不行?(我试过了,但似乎没有。)@RMHarris157我们在公司代码库中使用的一个选项是调用虚拟函数
v_processMsg
,该函数允许稍后将其覆盖,并将非虚拟的
processMsg
转发给它。这样,接口/转发器
processMsg
就可以放在正确的位置,并且不会干扰虚拟部分和类层次结构
并将转发器中的调用更改为
MyMessageInterface::vProcessMsg(_msg)当我试图编译包含上述派生定义的.C时,链接器抱怨它找不到元组中每个类的vProcessMsg的基类实现。我是否错过了另一层间接的东西?
template <typename... Ts>
struct MyMessageHandler : MyMessageInterface<Ts>... {

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

};