2016-10-04 2 views
4

Я играл с 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>());

myCurrent в приведенном выше Event() - метод представляет собой экземпляр следующего класса:

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

Update

Глядя на вещи под новым углом зрения, я закончил с чисто виртуальными функциями для Event<T>(...) методов, которые на самом деле то, что Я действительно хотел, чтобы класс EventBaseState был абстрактным.

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 тоже работает.

+0

'myCurrent-> Event (станд :: хода (событие));' Это важная строка , Какой тип 'myCurrent' и' event'? Как именно эти две переменные объявлены в функции, вызывающей 'myCurrent-> Event (std :: move (event)),' –

+0

@AaronMcDaid. В вопросе: 'myCurrent' -' EventBaseState', а 'event' -' std :: unique_ptr 'или' std :: unique_ptr '. – Rakete1111

ответ

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?

+0

Скорее всего, вы правы, и я буду отмечать это как ответ, когда я его пробовал. Я должен сказать, что сообщение компилятора действительно ведет вас по неправильному пути - на самом деле это говорит о наличии двух кандидатов, но затем игнорирует их. – Per

Смежные вопросы