Ihr kennt alle sicherlich folgendes Meme:
It doesn't work and I don't know why.
It does work and I don't know why.
Gerade erwischt mich letzter Satz: "It does work and I don't know why."
Erwartetes Ergebnis:
NullPointer-Exception. Abstürzen des Programmes
Tatsächliches Ergebnis:
Es funktioniert ohne Abzustürzen.
Per Templates erstelle ich einen Wrapper, damit Method mit unterschiedlicher Signatur in einem 'std::vector' speichern kann;
einzige Beschränkung: die Signatur hat nur einen Parameter.
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
|
//...
using EventPtr = void*;
using InstancePtr = void*;
//...
template<typename TEvent, class TClass, void(TClass::*TCallback)(TEvent*)>
static inline void MethodCallback(InstancePtr instance, EventPtr event){
(static_cast<TClass*>(instance)->*TCallback)(static_cast<TEvent*>(event));
}
|
Der Pointer auf die Instanz der Klasse sowie der Pointer zur Methode wird im 'std::pair' gespeichert.
|
C-/C++-Quelltext
|
1
2
|
using CallbackPtr = void(*)(InstancePtr, EventPtr);
using Callback = std::pair<InstancePtr, CallbackPtr>;
|
Ein Callback wird wiederum in einem std::vector-Container gespeichert (welcher wiederum in einer std::map gespeichert wird).
|
C-/C++-Quelltext
|
1
2
3
4
|
using CallbackList = std::vector<Callback>;
using UUID = uint32_t;
using Connections = std::map<uint32_t, CallbackList>;
Connections connections;
|
Zum Befühlen der Liste verwende ich folgenden Code:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
|
template<struct TEvent, class TClass, void(TClass::*TCallback)(TEvent*)>
void bind(TClass* instance){
uint32_t uuid{TEvent::uuid()};
connections[uuid].emplace_back(nullptr,// Eigentlich sollte hier [b]instance[/b] stehen.
&MethodCallback<TEvent, TClass, TCallback>);
}
|
Und die Callbacks werden so aufgerufen:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
|
template<typename TEvent>
void emit(TEvent* event){
for(auto cb : connections[TEvent::uuid()])
cb.second(cb.first, event); // <- Hier nullptr exception erwartet.
// Vergleich mit vorherigen Codebeispiel
// std::pair.first -> Pointer zur Instanz der Klasse
// std::pair.second -> Pointer zur Methode
}
|
Seltsamerweise kompiliert das Beispiel bei mir und läuft ohne Abzustürzen.
P.S.: Verzeiht Typo's, meine Kaffeemaschine ist leider kaputt.