对继承的模板方法的不明确调用

Ambiguous call to inherited template method

本文关键字:调用 不明确 模板方法 继承      更新时间:2023-10-16

我正在研究一个简单的事件系统来练习使用stdlib。

我做了一个EventEmitter<T>类,提供addListener(T)emitEvent(T)

有一个扩展EventEmitter<int>EventEmitter<std::string>TestEmitter类。TestEmitter类有一个调用 emitEvent(1337)emitEvent(std::string("test"))emitTestEvent 方法。

在 main() 中,创建了一个 TestEmitter 的实例,并为 T=int 和 T=std::string 添加了两个侦听器。

我收到 4 个看起来像这样的错误:reference to ‘emitEvent’ is ambiguous.emitEvent呼叫中两次,addListener呼叫中两次。

以下是完整输出:

main.cpp: In member function ‘virtual void TestEmitter::emitTestEvent()’:
main.cpp:42:4: error: reference to ‘emitEvent’ is ambiguous
main.cpp:23:15: error: candidates are: void EventEmitter<T>::emitEvent(T) [with T = std::basic_string<char>]
main.cpp:23:15: error:                 void EventEmitter<T>::emitEvent(T) [with T = int]
main.cpp:45:4: error: reference to ‘emitEvent’ is ambiguous
main.cpp:23:15: error: candidates are: void EventEmitter<T>::emitEvent(T) [with T = std::basic_string<char>]
main.cpp:23:15: error:                 void EventEmitter<T>::emitEvent(T) [with T = int]
main.cpp: In function ‘int main(int, char**)’:
main.cpp:53:10: error: request for member ‘addListener’ is ambiguous
main.cpp:19:15: error: candidates are: void EventEmitter<T>::addListener(EventEmitter<T>::Listener) [with T = std::basic_string<char>; EventEmitter<T>::Listener = std::function<void(std::basic_string<char>)>]
main.cpp:19:15: error:                 void EventEmitter<T>::addListener(EventEmitter<T>::Listener) [with T = int; EventEmitter<T>::Listener = std::function<void(int)>]
main.cpp:57:10: error: request for member ‘addListener’ is ambiguous
main.cpp:19:15: error: candidates are: void EventEmitter<T>::addListener(EventEmitter<T>::Listener) [with T = std::basic_string<char>; EventEmitter<T>::Listener = std::function<void(std::basic_string<char>)>]
main.cpp:19:15: error:                 void EventEmitter<T>::addListener(EventEmitter<T>::Listener) [with T = int; EventEmitter<T>::Listener = std::function<void(int)>]

我很困惑为什么我会收到这个错误,编译器 (g++) 清楚地知道T是哪个调用,但它不知道调用哪个方法?

我能够通过在emitEvent调用前面加上EventEmitter<int>::EventEmitter<std::string>来修复它们上的错误,但我不确定这是否是解决此问题的正确方法。

当编译器知道T的类型时,为什么对emitEventaddListener的调用不明确?我该如何解决这个问题?

我希望我提供了足够的信息,如果没有让我知道。代码如下:

#include <list>
#include <map>
#include <string>
#include <functional>
#include <iostream>
template<typename T>
class EventEmitter {
private:
        typedef std::function<void(T)> Listener;
protected:
        std::list<Listener> listeners_;
public:
        EventEmitter() {};
        virtual ~EventEmitter() {};
        virtual void addListener(Listener listener) {
                listeners_.push_back(listener);
        };
        virtual void emitEvent(T event) {
                typename std::list<Listener>::iterator it = listeners_.begin();
                for(; it != listeners_.end(); ++it) {
                        (*it)(event);
                }
        };
};
class TestEmitter : public EventEmitter<int>, public EventEmitter<std::string> {
private:
        int count_;
public:
        TestEmitter() {};
        virtual ~TestEmitter() {};
        virtual void emitTestEvent() {
                count_ = (++count_) % 2;
                if(count_ == 0) {
                        EventEmitter<int>::emitEvent(1337);
                }
                else {
                        EventEmitter<std::string>::emitEvent(std::string("test"));
                }
        };
};
int main(int argc, char* argv[]) {
        TestEmitter emitter;
        emitter.addListener([](int event) {
                std::cout << "Hello: " << event << std::endl;
        });
        emitter.addListener([](std::string event) {
                std::cout << "Bye: " << event << std::endl;
        });
        for(int i = 0; i < 10; i++) {
                emitter.emitTestEvent();
        }
        return 0;
}

谢谢:)

您的类继承了两个不同的其他类。现在,有两种方法:

EventEmitter::emitTestEvent 和 EventEmitter::emitTestEvent

应该叫哪一个?这本身并不清楚。

您可以执行以下操作:

emitter.EventEmitter<int>::emitEvent(/* ... */);

但是,您可能会过度考虑您的设计...当类的用户调用 eventEmit 时,它应该做什么?然后,相应地设计您的类,以便它们提供此行为。

编辑:另一种解决方案可以通过using找到,例如:

#include <iostream>
#include <string>
using namespace std;
class A
{
public:
    void foo(int) {cout << "A::foo";}
};
class B
{
public:
    void foo(string) {cout << "B::foo";}
};
class C : public A, public B
{
public:
    using A::foo;
    using B::foo;
};
int main() {
    C c;
    c.foo(10);
    c.foo("hi");
    return 0;
}