来自可变参数模板的不明确的成员请求

时间:2014-07-09 21:12:22

标签: c++ templates c++11 variadic-templates

这对我没有意义。 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() );
}

4 个答案:

答案 0 :(得分:4)

您可以按以下方式重写MyMessageHandlerLive 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...>
{
};

答案 1 :(得分:4)

您可以将转发器添加到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

你需要做这样的事情(或者Jarod42提出的)的原因是,当名称不明确时,基类的虚方法在派生类中是不可见的。通常情况下,您需要添加一个使用声明来提供所需内容,但在您的情况下,转发器可能更容易。

答案 2 :(得分:1)

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

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

答案 3 :(得分: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