2014-07-09 22 views
4

这对我来说没有任何意义。海湾合作委员会抱怨说,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

你可以转发器添加到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提出)的原因是基本的虚拟方法当名称不明确时,派生类中不可见类。通常情况下,您会添加一个使用声明来提取所需内容,但在您的情况下,转发器可能更容易。

+0

嗯......所以这个计划是(下一步)从上面派生一个具体的MessageHandler对象,并在派生类中重载processMsg()调用。我猜这是行不通的? (我试过了,看起来好像没有。) – RMHarris157

+0

@ RMHarris157我们公司代码库中使用的一个选项是调用虚函数'v_processMsg',它可以在稍后被覆盖,并具有非虚拟的'processMsg '转发给它。这样,接口/转发器'processMsg'可以放在正确的位置,不会影响虚拟部分和类层次结构。 –

+0

因此,在上面的上下文中,我将MyMessageInterface更改为:'virtual void vProcessMsg(const MessageT&)= 0;'并将转发器中的调用更改为'MyMessageInterface < MessageT > :: vProcessMsg(_msg);'当我尝试为了编译包含上述派生定义的.C,连接器抱怨它无法为元组中的每个类找到vProcessMsg的基类实现。我在某个地方错过了另一个间接层? – RMHarris157

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

不如直接把模板方法在类:'模板<类型名... T> 结构MyMessageHandler:公共MyMessageInterface ... { 模板 空隙processMsg(常量T2&T) { MyMessageInterface :: processMsg(t); } }; '(https://ideone.com/oaqkk2) – Jarod42

4

您可以改写MyMessageHandler如下:Live 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...> 
{ 
}; 
+0

解释为什么解决这个问题将有助于理解它。 – leemes

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