模板实例化歧义

时间:2016-10-04 06:05:28

标签: c++

我正在玩templated implementation FSM并遇到如下歧义:

/home/permal/code/FSM/Test/../FSM/dist/include/FSM.h: In instantiation of ‘void fsm::FSM<FSMBaseState>::Event(std::unique_ptr<EventType>) [with EventType = AddEvent; FSMBaseState = EventBaseState]’:
/home/permal/code/FSM/Test/test.cpp:83:44:   required from here
/home/permal/code/FSM/Test/../FSM/dist/include/FSM.h:59:4: error: request for member ‘Event’ is ambiguous
    myCurrent->Event( std::move( event ) );
    ^
In file included from /home/permal/code/FSM/Test/../FSM/dist/include/FSM.h:12:0,
                 from /home/permal/code/FSM/Test/test.cpp:8:
/home/permal/code/FSM/Test/../FSM/dist/include/EventReceiver.h:15:15: note: candidates are: void fsm::EventReceiver<EventType>::Event(std::unique_ptr<_Tp>) [with EventType = SubtractEvent]
  virtual void Event( std::unique_ptr<EventType> event ) = 0;
               ^
/home/permal/code/FSM/Test/../FSM/dist/include/EventReceiver.h:15:15: note:                 void fsm::EventReceiver<EventType>::Event(std::unique_ptr<_Tp>) [with EventType = AddEvent]
In file included from /home/permal/code/FSM/Test/test.cpp:8:0:
/home/permal/code/FSM/Test/../FSM/dist/include/FSM.h: In instantiation of ‘void fsm::FSM<FSMBaseState>::Event(std::unique_ptr<EventType>) [with EventType = SubtractEvent; FSMBaseState = EventBaseState]’:
/home/permal/code/FSM/Test/test.cpp:91:50:   required from here
/home/permal/code/FSM/Test/../FSM/dist/include/FSM.h:59:4: error: request for member ‘Event’ is ambiguous
    myCurrent->Event( std::move( event ) );

所以我的问题是为什么编译器无法选择正确的选项,即使它说明有两个可能的候选者,其中一个是正确的候选者。

我希望下面的代码足以显​​示问题,其余部分可在GitHub

上找到

这是出现歧义的类和方法:

template<typename FSMBaseState>
class FSM
{
public:
    ...

    template<typename EventType>
    void Event( std::unique_ptr<EventType> event )
    {
        if( HasState() )
        {
            // This way of calling causes ambiguous method lookup during template instantiation
            myCurrent->Event( std::move( event ) );

            // casting to the correct type works, but is it really needed?
            // auto* s = myCurrent.get();
            // static_cast<EventReceiver<EventType>*>( s )->Event( std::move( event ) );
        }
    }

};

以上方法称为fsm.Event( std::make_unique<AddEvent>() );fsm.Event( std::make_unique<SubractEvent>() );

上面的Event()中的

myCurrent - 方法是以下类的实例:

class EventBaseState
: public fsm::BaseState<EventBaseState>,
      public fsm::EventReceiver<AddEvent>,
      public fsm::EventReceiver<SubtractEvent>
{
public:
EventBaseState( const std::string& name, fsm::FSM<EventBaseState>& fsm ) :
        BaseState( name, fsm )
{}

};

其中EventReceiver的定义如下:

template<typename EventType>
class EventReceiver
{
public:
    virtual void Event( std::unique_ptr<EventType> event ) = 0;
};

更新

从一个新的角度来看,我最终得到了Event<T>(...)方法的纯虚函数,这实际上是我真正想要的,因为EventBaseState类应该是抽象的。< / p>

class EventBaseState
    : public fsm::BaseState<EventBaseState>,
      public fsm::EventReceiver<AddEvent>,
      public fsm::EventReceiver<SubtractEvent>
{
public:
    EventBaseState( const std::string& name, fsm::FSM<EventBaseState>& fsm ) :
            BaseState( name, fsm )
    {}

    virtual void Event( std::unique_ptr<AddEvent> event ) override = 0;
    virtual void Event( std::unique_ptr<SubtractEvent> event ) override = 0;
};

当然,Chajnik-U提供的解决方案也有效。

1 个答案:

答案 0 :(得分:3)

当通过派生类实例调用时,基类的方法不参与“跨类”重载。 你必须放置

using EventReceiver<AddEvent>::Event;
using EventReceiver<SubtractEvent>::Event;
EventBaseState内部

强制两个方法都可以通过重载看到。 有关标准的详细信息(简化示例),请参见此处:

Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions?