запрос на член `... 'неоднозначен в g ++ - PullRequest
10 голосов
/ 21 августа 2009

Я получаю следующую ошибку компиляции в одном из моих классов, используя gcc 3.4.5 (mingw):

src/ModelTester/CModelTesterGui.cpp:1308: error: request for member `addListener' is ambiguous
include/utility/ISource.h:26: error: candidates are: void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SConsolePacket&]
include/utility/ISource.h:26: error:                 void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SControlPacket&]

Надеюсь, вы видите, что ISource<T> - это интерфейс шаблона, который просто указывает, что объект может быть информером для объекта, который имеет некоторый соответствующий тип IListener<T>. Поэтому меня раздражает то, что по какой-то причине функции неоднозначны, когда, насколько я могу судить, их нет. Метод addListener() перегружен для разных типов ввода IListener<const SConsolePacket&> и IListener<const SControlPacket&>. Использование:

m_controller->addListener( m_model );

Где m_model - указатель на объект IRigidBody, а IRigidBody наследуется только от IListener< const SControlPacket& > и определенно не от IListener< const SConsolePacket& >

В качестве проверки работоспособности я использовал doxygen для генерации диаграммы иерархии классов, и doxygen соглашается со мной, что IRigidBody не происходит от IListener< const SConsolePacket& >

Очевидно, мое понимание наследования в c ++ не совсем верно. У меня сложилось впечатление, что IListener<const SControlPacket&> и IListener<const SConsolePacket&> - это два разных типа, и что объявления функций

addListener(IListener<const SConsolePacket&>* listener)

и

addListener(IListener<const SControlPacket&>* listener)

объявляет две отдельные функции, которые выполняют две разные функции в зависимости от (различного) различного типа входного параметра. Кроме того, у меня сложилось впечатление, что указатель на IRigidBody также является указателем на IListener<const SControlPacket&> и что при вызове addListener( m_model ) компилятор должен понимать, что я вызываю вторую из двух вышеупомянутых функций.

Я даже пробовал кастовать m_model вот так:

m_controller->addListener(
        static_cast<IListener<const SControlPacket&>*>(m_model) );

но все равно получите эту ошибку. Я не могу на всю жизнь увидеть, как эти функции неоднозначны. Кто-нибудь может пролить свет на этот вопрос?

P.S. Я знаю, как заставить функцию быть однозначной, выполняя это:

m_controller->ISource<const SControlPacket&>::addListener( m_model );

Мне просто кажется, что это ужасно нечитаемо, и я бы предпочел не делать этого.

Редактировать ... шучу. Это, очевидно, не решает проблему, поскольку приводит к ошибке компоновщика:

CModelTesterGui.cpp:1312: undefined reference to `utility::ISource<aerobat::SControlPacket const&>::addListener(utility::IListener<SControlPacket const&>*)'

1 Ответ

24 голосов
/ 21 августа 2009

Похоже, ваша ситуация такова:

struct A {
  void f();
};

struct B {
  void f(int);
};

struct C : A, B { };

int main() { 
  C c; 
  c.B::f(1); // not ambiguous
  c.f(1);    // ambiguous
}

Второй вызов функции f неоднозначен, поскольку при поиске имени он находит функции в двух разных областях действия базового класса. В этой ситуации поиск неоднозначен - они не перегружают друг друга. Исправление будет заключаться в использовании декларации использования для каждого имени члена. Lookup будет искать имена в области C и не искать дальше:

struct C : A, B { using A::f; using B::f; };

Теперь вызов найдет две функции, выполнит разрешение перегрузки и обнаружит, что подойдет int. Перенесенный в ваш код, это будет означать, что вы должны сделать что-то вроде следующего:

struct controller : ISource<const SConsolePacket&>, ISource<const SControlPacket&> {
  using ISource<const SConsolePacket&>::addListener;
  using ISource<const SControlPacket&>::addListener;
};

Теперь эти два имени находятся в одной области видимости, и теперь они могут перегружать друг друга. Поиск теперь остановится на классе контроллера, не углубляясь в две ветви базового класса.

...