запрос для участника `...' неоднозначен в g ++
Вопрос
Я получаю следующую ошибку компиляции в одном из моих классов, используя 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&>*)'
Решение
Похоже, ваша ситуация такова:
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 неоднозначен, потому что при поиске по имени он находит функции в двух разных областях базового класса.В этой ситуации поиск неоднозначен - они не перегружают друг друга.Исправлением было бы использование объявления using для каждого имени участника.Поиск позволит найти имена в области 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;
};
Теперь эти два имени находятся в одной области видимости, и теперь они могут перегружать друг друга.Поиск теперь остановится на классе controller, не углубляясь далее в две ветви базового класса.