基本分辨率/模板类型扣除

时间:2013-11-13 07:32:54

标签: c++ templates c++11 template-meta-programming

我不确定模板类型演绎是否会在这里加入战斗。但让我解释一下。

我有一个模板class EventProducer,从中为每个事件类型派生事件派生的对象一次,以便我可以这样:class HellRaiser: public EventProducer<MouseMoveEvent>, public EventProducer<MouseButtonEvent>。这似乎工作得很好,除了在调用派生类的对象时必须使用基类型限定EventProducer调用。但是编译器不应该自动推导出基数EventProducer

这是定义:

template <typename TEvent>
class EventProducer
{
public:
    typedef function<typename TEvent::HandlerSignature> HandlerFunction;

    //  Methods.
    connection Subscribe(const HandlerFunction& callback);
    void Trigger(TEvent& event);

protected:
    // ...
};

在事件类中定义TEvent::HandlerSignature

  1. 为什么此调用不明确:hellRaiserObject->Trigger(MouseMoveEvent(11, -4));假设对象派生自EventProducer<MouseMoveEvent>EventProducer<MouseButtonEvent>
  2. 我可以做些什么来帮助编译器决定调用哪个,而不明确指定基础?
  3. 此次通话也是如此:hellRaiserObject->Subscribe(mouseCallback);。我理解在这里推断出类型可能有点困难,但mouseCallback有一个特定的签名,可以与模板特化进行比较,我认为它只适合其中一个。
  4. 以防它有所不同,事件的定义如下:class MouseMoveEvent: public Event<MouseMoveEvent>,其中基本模板是

    template <typename TEventArgs>
    class Event
    {
    public:
        typedef TEventArgs EventArgs;
        typedef void HandlerSignature(TEventArgs&);
    
        // ...
    };
    

    非常感谢。

2 个答案:

答案 0 :(得分:3)

来自多个基类的名称查找必须是明确的

10.2会员名称查找[class.member.lookup]

  

1会员名称查找确定名称的含义(id-expression)   在一个范围内(3.3.7)。名称查找可能导致歧义   该程序的格式错误。

标准的这一部分中有很多关于如何合并各种基类的名称的技术细节,但最后,如果出现歧义,程序就会形成错误。因此,您需要限定您的名字才能解决此问题。

请注意,各种函数的最佳匹配签名将在重载解析期间发挥作用,但只有在成功且明确的名称查找之后才会发生。

答案 1 :(得分:0)

这不是模板特有的:

#include <string>

class HandlerString
{
public:
    void Handle(const std::string& event) {}
};

class HandlerInt
{
public:
    void Handle(int event) {}
};

class ConcreteHandler : public HandlerString, public HandlerInt {};

int main(int argc, char const *argv[])
{
    ConcreteHandler handler;

    handler.Handle(std::string("foo"));
    handler.Handle(1);
    return 0;
}

g ++ 4.8.1的输出:

test.cpp: In function 'int main(int, const char**)':
test.cpp:21:10: error: request for member 'Handle' is ambiguous
  handler.Handle(std::string("foo"));
          ^
test.cpp:12:7: note: candidates are: void HandlerInt::Handle(int)
  void Handle(int event) {}
       ^
test.cpp:6:7: note:                 void HandlerString::Handle(const string&)
  void Handle(const std::string& event) {}
       ^
test.cpp:22:10: error: request for member 'Handle' is ambiguous
  handler.Handle(1);
          ^
test.cpp:12:7: note: candidates are: void HandlerInt::Handle(int)
  void Handle(int event) {}
       ^
test.cpp:6:7: note:                 void HandlerString::Handle(const string&)
  void Handle(const std::string& event) {}
       ^