Nie dawno napisałem system zdarzeń (ktoś klika na okno -> wywołuje się funkcja/-e ). Większość ładnie działa, ale od dwóch dni zmagam się z pewnym problemem. Otóż chciałbym usunąć pewne callbacki po dodaniu ich do systemu. Próbowałem już kilku sposobów, ale cały czas coś jest źle.
#include <iostream>
#include <iomanip>
#include <functional>
#include <map>
#include <utility>
#include <algorithm>
#include <vector>
enum EventType {
eKeyPressedType,
eKeyReleasedType,
eWindowMovedType,
eWindowResizedType,
eWindowClosedType
};
enum EventCategory {
eKeyEventCategory,
eWindowEventCategory
};
class Event {
public:
virtual EventType GetType() = 0;
virtual EventCategory GetCategory() = 0;
};
class KeyEvent : public Event {
public:
virtual EventCategory GetCategory() { return eKeyEventCategory; }
};
class KeyPressedEvent : public KeyEvent {
public:
static EventType StaticGetType() { return eKeyPressedType; }
virtual EventType GetType() { return StaticGetType(); }
};
class KeyReleasedEvent : public KeyEvent {
public:
static EventType StaticGetType() { return eKeyReleasedType; }
virtual EventType GetType() { return StaticGetType(); }
};
class IEventCallback {
public:
virtual void call(Event& e) = 0;
virtual void setId(uint8_t id) = 0;
virtual uint8_t getId() = 0;
};
template<typename T>
class EventCallback : public IEventCallback {
std::function<void(T&)> m_fn;
uint8_t m_id;
public:
EventCallback(std::function<void(T&)> fn)
: m_fn(fn), m_id(0) {}
virtual void call(Event& e) {
if(m_fn != nullptr)
m_fn(*(reinterpret_cast<T*>(&e)));
}
virtual void setId(uint8_t id) {
m_id = id;
}
virtual uint8_t getId() {
return m_id;
}
};
class EventManager {
public:
EventManager()
: m_idCount(0) {}
void Register(EventType type, IEventCallback& cb) {
if(cb.getId() == 0)
cb.setId(++m_idCount);
m_callbacks.emplace_back(type, cb);
}
// Unregister specific type from callback
void Unregister(EventType type, IEventCallback& cb) {
if(m_callbacks.empty())
return;
/*auto it = std::find_if(m_callbacks.begin(), m_callbacks.end(), [&cb, &type](std::pair<EventType, IEventCallback&>& pair) {
return ((pair.second.getId() == cb.getId()) && (pair.first == type));
});
if(it != m_callbacks.end())
m_callbacks.erase(it);
else
return;*/
}
// Unregister callback from all types
void UnregisterCallback(IEventCallback& cb) {
if(m_callbacks.empty())
return;
/*
for(auto it = m_callbacks.begin(); it != m_callbacks.end(); it++) {
if((*it).second.getId() == cb.getId())
m_callbacks.erase(it);
}*/
/*
auto it = m_callbacks.begin();
while(it != m_callbacks.end()) {
if((*it).second.getId() == cb.getId())
m_callbacks.erase(it);
it++;
}*/
/*
for(size_t i = 0; i < m_callbacks.size(); i++) {
auto& pair = m_callbacks[i];
if(pair.second.getId() == cb.getId()) {
auto it = m_callbacks.begin() + i;
m_callbacks.erase(it);
if(i != 0)
i--;
}
}*/
}
void Dispatch(Event& e) {
for(auto pair : m_callbacks) {
if(pair.first == e.GetType()) {
pair.second.call(e);
}
}
}
private:
uint8_t m_idCount;
std::vector<std::pair<EventType, IEventCallback&>> m_callbacks;
};
int main(int argc, char** argv) {
{
EventManager eManager;
auto generalCallback = [](Event& e) {
std::cout << "Event type: ";
switch(e.GetType()) {
case eKeyPressedType:
std::cout << "KeyPressedEvent" << std::endl;
break;
case eKeyReleasedType:
std::cout << "KeyReleasedEvent" << std::endl;
break;
default:
std::cout << "Unknown" << std::endl;
}
};
auto keyPressedCallback = [](KeyPressedEvent& e) {
std::cout << "Key pressed" << std::endl;
};
auto keyReleasedCallback = [](KeyPressedEvent& e) {
std::cout << "Key released" << std::endl;
};
EventCallback<KeyPressedEvent> generalCb(generalCallback);
EventCallback<KeyPressedEvent> keyPressedCb(keyPressedCallback);
EventCallback<KeyPressedEvent> keyReleasedCb(keyReleasedCallback);
eManager.Register(eKeyPressedType, generalCb);
eManager.Register(eKeyReleasedType, generalCb);
eManager.Register(eKeyPressedType, keyPressedCb);
eManager.Register(eKeyReleasedType, keyReleasedCb);
KeyPressedEvent ekp;
KeyReleasedEvent ekr;
eManager.Dispatch(ekp);
eManager.Dispatch(ekr);
//eManager.Unregister(eKeyPressedType, generalCb);
//std::cout << "Second run" << std::endl;
//eManager.Dispatch(ekp);
//eManager.Dispatch(ekr);
}
std::cin.get();
return 0;
}
Edit: "ale cały czas coś jest źle", nie mogę tego bardzo opisać. Przy jednym sposobie wyjdzie wyjątek, przy drugim nie poprawnie działa (usuwa zły element).