【发布时间】:2016-06-19 05:08:57
【问题描述】:
我正在开发一个简单的事件系统来练习使用标准库。
我创建了一个EventEmitter<T> 类,它提供addListener(T) 和emitEvent(T)。
有一个TestEmitter 类扩展了EventEmitter<int> 和EventEmitter<std::string>。 TestEmitter 类有一个emitTestEvent 方法,该方法调用emitEvent(1337) 或emitEvent(std::string("test"))。
在 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 对任何一个调用是什么,但它不知道调用哪个方法?
我能够通过在EventEmitter<int>:: 和EventEmitter<std::string> 前面加上emitEvent 调用来修复错误,但我不确定这是否是解决此问题的正确方法。
当编译器知道T 的类型时,为什么对emitEvent 和addListener 的调用不明确?我该如何解决这个问题?
我希望我提供了足够的信息,如果没有,请告诉我。代码如下:
#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;
}
谢谢:)
【问题讨论】:
-
编译器无法确定调用哪个继承方法。我不知道具体原因,但一种解决方法是调用
emitter.EventEmitter<int>::addListener([](int event) { /* ... */ });和emitter.EventEmitter<std::string>::addListener([](std::string event) { /* ... */ });。 -
由于序列点规则,
count_ = (++count_ ) % 2;也有未定义的行为。而是使用count_ = (count_ + 1) % 2; -
@jotik 感谢解决方法 :) 我会研究序列点规则,我不知道!谢谢你告诉我。
-
一个合理的解释是编译器按名称查找具有该方法的相应类。现在,对于 emitEvent 它看到两个条目......重载部分可能在确定方法名称属于哪个类之后发生。不过,我不明白为什么编译器不能自己解决这个问题
-
好吧,事实证明,运算符重载是不允许跨作用域的,继承不会合并作用域,但超类算作特定作用域。我已经在下面更新了我的答案,您可以使用 using。
标签: c++ templates c++11 multiple-inheritance ambiguous