我有
EventBus
类管理回调, EBHandle
类旨在在添加回调的对象被销毁时自动清理回调。所以,我认为循环依赖在这里是合理的。我也有BaseEvent
,但这并不重要,只是为了代码可以运行。
#pragma once
#include <unordered_map>
#include <functional>
#include <typeindex>
struct BaseEvent {
BaseEvent() = default;
virtual ~BaseEvent() = default;
};
class EventBus;
class EBHandle {
private:
int m_key = -1;
bool m_isRemoved = false;
std::type_index m_type = typeid(int);
EventBus* m_eventBus = nullptr;
public:
EBHandle(EventBus *eventBus, std::type_index type, int key);;
void remove();
};
class EventBus {
std::unordered_map<std::type_index, std::unordered_map<int, std::function<void(const BaseEvent &)>>> m_callbacks;
int m_keyCounter = 0;
public:
EventBus() = default;
template<typename EventType>
EBHandle addEventListener(const std::function<void(const EventType &)> &callback) {
// passing m_callback by copy is necessary. otherwise if callback passed to addEventListener by reference and it is destroyed, lambda will have dangling reference
auto wrapper = [callback](const BaseEvent &baseEvent) {
callback(static_cast<const EventType &>(baseEvent));
};
std::type_index type = typeid(EventType);
m_callbacks[type][m_keyCounter] = wrapper;
return {this, type, m_keyCounter++};
};
template<typename EventType>
void removeEventListener(int key) {
m_callbacks[typeid(EventType)].erase(key);
};
void removeEventListener(std::type_index type, int key) {
m_callbacks[type].erase(key);
};
void emit(const BaseEvent &event) {
auto &eventTypeCallbacks = m_callbacks[typeid(event)];
for (auto &pair: eventTypeCallbacks) {
pair.second(event);
}
};
EventBus(const EventBus &) = delete;
EventBus &operator=(const EventBus &) = delete;
EventBus(EventBus &&) = delete;
EventBus &operator=(EventBus &&) = delete;
};
EBHandle::EBHandle(EventBus *eventBus, std::type_index type, int key) : m_key(key), m_type(type), m_eventBus(eventBus) {}
void EBHandle::remove() {
m_eventBus->removeEventListener(m_type, m_key);
m_isRemoved = true;
}
在尝试打破依赖性时,我首先尝试将声明和定义拆分为 .cpp 和 .h 文件。然后意识到我的方法是模板化的。然后尝试像上面的代码(在单个文件中)一样执行此操作,并且它有效。但是,我想将 EBHandle 和 EventBus 拆分到不同的文件。 这个问题的答案说这是可行的。我试过了:
EventBus.h:
#pragma once
#include <unordered_map>
#include <functional>
#include <typeindex>
#include "EBHandle.h"
struct BaseEvent {
BaseEvent() = default;
virtual ~BaseEvent() = default;
};
class EventBus {
std::unordered_map<std::type_index, std::unordered_map<int, std::function<void(const BaseEvent &)>>> m_callbacks;
int m_keyCounter = 0;
public:
EventBus() = default;
template<typename EventType>
EBHandle addEventListener(const std::function<void(const EventType &)> &callback) {
// passing m_callback by copy is necessary. otherwise if callback passed to addEventListener by reference and it is destroyed, lambda will have dangling reference
auto wrapper = [callback](const BaseEvent &baseEvent) {
callback(static_cast<const EventType &>(baseEvent));
};
std::type_index type = typeid(EventType);
m_callbacks[type][m_keyCounter] = wrapper;
return {this, type, m_keyCounter++};
};
template<typename EventType>
void removeEventListener(int key) {
m_callbacks[typeid(EventType)].erase(key);
};
void removeEventListener(std::type_index type, int key) {
m_callbacks[type].erase(key);
};
void emit(const BaseEvent &event) {
auto &eventTypeCallbacks = m_callbacks[typeid(event)];
for (auto &pair: eventTypeCallbacks) {
pair.second(event);
}
};
EventBus(const EventBus &) = delete;
EventBus &operator=(const EventBus &) = delete;
EventBus(EventBus &&) = delete;
EventBus &operator=(EventBus &&) = delete;
};
EBHandle.h:
class EventBus;
class EBHandle {
private:
int m_key = -1;
bool isRemoved = false;
std::type_index m_type = typeid(int);
EventBus* m_eventBus = nullptr;
public:
EBHandle(EventBus *eventBus, std::type_index type, int key);
void remove();
};
#include "EventBus.h"
EBHandle::EBHandle(EventBus *eventBus, std::type_index type, int key) : m_key(key), m_type(type), m_eventBus(eventBus) {};
void EBHandle::remove() {
m_eventBus->removeEventListener(m_type, m_key);
isRemoved = true;
}
抱歉,代码太多了。我不想错过任何重要的事情。
在 EBHandle 中调用 removeEventListener 的地方,我仍然收到“无效使用不完整类型”错误 我做错了什么?
您只需将
EBHandle
的成员函数定义移动到单独的源文件中,如下所示。 工作演示
EBHandle.cpp
#include "EBHandle.h"
EBHandle::EBHandle(EventBus *eventBus, std::type_index type, int key) : m_key(key), m_type(type), m_eventBus(eventBus) {};
void EBHandle::remove() {
m_eventBus->removeEventListener(m_type, m_key);
isRemoved = true;
}
EBHandle.h
#pragma once
#include <typeindex>
class EventBus;
class EBHandle {
private:
int m_key = -1;
bool isRemoved = false;
std::type_index m_type = typeid(int);
EventBus* m_eventBus = nullptr;
public:
EBHandle(EventBus *eventBus, std::type_index type, int key);
void remove();
};
#include "EventBus.h"
EventBus.h
#pragma once
#include <unordered_map>
#include <functional>
#include <typeindex>
#include "EBHandle.h"
struct BaseEvent {
BaseEvent() = default;
virtual ~BaseEvent() = default;
};
class EventBus {
std::unordered_map<std::type_index, std::unordered_map<int, std::function<void(const BaseEvent &)>>> m_callbacks;
int m_keyCounter = 0;
public:
EventBus() = default;
template<typename EventType>
EBHandle addEventListener(const std::function<void(const EventType &)> &callback) {
// passing m_callback by copy is necessary. otherwise if callback passed to addEventListener by reference and it is destroyed, lambda will have dangling reference
auto wrapper = [callback](const BaseEvent &baseEvent) {
callback(static_cast<const EventType &>(baseEvent));
};
std::type_index type = typeid(EventType);
m_callbacks[type][m_keyCounter] = wrapper;
return {this, type, m_keyCounter++};
};
template<typename EventType>
void removeEventListener(int key) {
m_callbacks[typeid(EventType)].erase(key);
};
void removeEventListener(std::type_index type, int key) {
m_callbacks[type].erase(key);
};
void emit(const BaseEvent &event) {
auto &eventTypeCallbacks = m_callbacks[typeid(event)];
for (auto &pair: eventTypeCallbacks) {
pair.second(event);
}
}
};