请求会员“...”在 g++ 中是不明确的

发布于 2024-08-03 00:34:34 字数 2452 浏览 3 评论 0原文

我使用 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 是一个模板接口,仅指示该对象可以是某种匹配类型 IListener 的对象的通知者。因此,让我感到恼火的是这样的想法:由于某种原因,函数是不明确的,而据我所知,它们并非如此。 addListener() 方法针对不同的输入类型 IListenerIListener 进行重载。用法是:

m_controller->addListener( m_model );

其中m_model是指向IRigidBody对象的指针,而IRigidBody仅继承自IListenerIRigidBody。 const SControlPacket& > 并且绝对不是来自 IListener< const SConsolePacket& >

作为健全性检查,我使用 doxygen 生成类层次结构图,并且 doxygen 同意我的观点,即 IRigidBody 不是从 IListener派生的。 const SConsolePacket& >

显然我对c++继承的理解并不完全正确。我的印象是 IListenerIListener 是两种不同的类型,并且函数声明

addListener(IListener<const SConsolePacket&>* listener)

addListener(IListener<const SControlPacket&>* listener)

声明两个单独的类型根据输入参数的(不同)不同类型执行两个单独的操作的函数。此外,我的印象是,指向 IRigidBody 的指针也是指向 IListener的指针,并且通过调用 addListener( m_model ) 编译器应该明白我正在调用上述两个函数中的第二个。

我什至尝试像这样转换 m_model

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

但仍然收到该错误。我一辈子都看不出这些功能有多么含糊。谁能阐明这个问题?

PS 我知道如何通过这样做来强制函数明确:

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

我只是碰巧认为这是非常不可读的,我宁愿不必这样做。

编辑……开个玩笑。这显然不能解决问题,因为它会导致链接器错误:

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

I'm getting the following compile error in one of my classes, using 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&]

Hopefully you can see that ISource<T> is a template interface that just indicates that the object can be an informer for an object that is of some matching type IListener<T>. So the thing that has me irked is this idea that for some reason functions are ambiguous when, as far as I can tell, they are not. The addListener() method is overloaded for different input types IListener<const SConsolePacket&> and IListener<const SControlPacket&>. The usage is:

m_controller->addListener( m_model );

Where m_model is a pointer to an IRigidBody object, and IRigidBody inherits only from IListener< const SControlPacket& > and definately not from IListener< const SConsolePacket& >

As a sanity check, I used doxygen to generate the class hierarchy diagram and doxygen agrees with me that IRigidBody does not derive from IListener< const SConsolePacket& >

Evidently my understanding of inheritence in c++ is not exactly correct. I'm under the impression that IListener<const SControlPacket&> and IListener<const SConsolePacket&> are two different types, and that the function declarations

addListener(IListener<const SConsolePacket&>* listener)

and

addListener(IListener<const SControlPacket&>* listener)

declare two separate functions that do two separate things depending on the (distinct) different type of the parameter that is input. Furthermore, I'm under the impression that a pointer to an IRigidBody is also a pointer to an IListener<const SControlPacket&> and that by calling addListener( m_model ) the compiler should understand that I'm calling the second of the above two functions.

I even tried casting m_model like this:

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

but still get that error. I cannot for the life of me see how these functions are ambiguous. Can anyone shed light on this issue?

P.S. I know how to force the function to be un-ambiguous by doing this:

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

I just happen to think that is terribly unreadible and I would prefer not to have to do that.

Edit... just kidding. That apparently doesn't fix the problem as it leads to a linker error:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

奶茶白久 2024-08-10 00:34:34

看起来你的情况是这样的:

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

现在,这两个名称位于同一范围内,现在它们可以互相重载。查找现在将停止在控制器类,而不是进一步深入到两个基类分支。

Looks like your situation is like this:

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
}

The second call to f is ambiguous, because in looking up the name, it finds functions in two different base class scopes. In this situation, the lookup is ambiguous - they don't overload each other. A fix would be to use a using declaration for each member name. Lookup will find names in the scope of C and don't lookup further:

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

Now, the call would find two functions, do overload resolution, and find that the one taking int will fit. Carried over to your code, it would mean that you have to do something like the following

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

Now, the two names are in the same scope, and now they can overload each other. Lookup will now stop at the controller class, not diving further into the two base-class branches.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文