Comments (4)
Hello,
If I remember correctly, there are other event libraries use your generic approach.
The generic approach is only usable in synchronized EventDispatcher, it can't be used in asynchronous EventQueue. Most applications will use asynchronous event queue, such as Windows system, GUI applications, games, all of them relies on event loop. EventQueue provides such event loop. This is the best reason I don't use the generic approach in eventpp.
Also, not every event needs a unique C++ type. For example, in a GUI application, it's common that there are events for key up, and key down, but they may share an event type such as KeyEvent. Also it's not rare that many events don't need any data, defining a class for such event is overkill.
My first decision when making eventpp was NOT to use the generic approach. That approach may have more disadvantages I didn't list above.
Fortunately, eventpp is so flexible that you can simulate the generic approach almost perfectly, below is the sample code. The only disadvantage is that you need free functions instead of member functions in EventDispatcher, of course you can inherit from EventDispatcher and put the functions in it.
#include "eventpp/eventdispatcher.h"
#include <typeinfo>
#include <typeindex>
#include <iostream>
// The `const void *` is for using data structures that don't have the same base class.
// The user code is not aware of any pointers.
using MyEventDispatcher = eventpp::EventDispatcher<std::type_index, void (const void *)>;
template <typename T, typename Listener>
void genericAppend(MyEventDispatcher & dispatcher, Listener && listener)
{
dispatcher.appendListener(std::type_index(typeid(T)), [listener](const void * e) {
listener(*static_cast<const T *>(e));
});
}
template <typename T>
void genericDispatch(MyEventDispatcher & dispatcher, const T & e)
{
dispatcher.directDispatch(std::type_index(typeid(T)), &e);
}
struct KeyEvent { int key; };
struct MessageEvent { std::string message; };
void doTest()
{
MyEventDispatcher dispatcher;
genericAppend<KeyEvent>(dispatcher, [](const KeyEvent & e) {
std::cout << "Generic key event, key is " << e.key << std::endl;
});
genericAppend<MessageEvent>(dispatcher, [](const MessageEvent & e) {
std::cout << "Generic message event, message is " << e.message << std::endl;
});
genericDispatch(dispatcher, KeyEvent{ 38 });
genericDispatch(dispatcher, MessageEvent{ "Hello eventpp" });
}
from eventpp.
The generic approach is only usable in synchronized EventDispatcher, it can't be used in asynchronous EventQueue.
If I add one additional std::list and these two methods:
std::list<std::function<void()>> queuedDispatches;
template<typename T>
void queue(const T& msg)
{
queuedDispatches.push_back([this, msg]() {
dispatch(msg);
});
}
void process()
{
for (auto& queuedDispatch : queuedDispatches)
{
queuedDispatch();
}
queuedDispatches.clear();
}
Then I can do asynchronous dispatching:
dispatcher.queue(Message()); // queues "Abstract message"
dispatcher.queue(MousePressedMsg{ 10, 20 }); // queues "Mouse pressed: (10, 20)"
dispatcher.queue(Chicken{});
std::cout << "Before process" << std::endl;
dispatcher.process(); // prints "Abstract message" and "Mouse pressed: (10, 20)"
std::cout << "After process" << std::endl;
So I still don't understand what is not possible according to asynchronous dispatching. Maybe some corner cases with removing listeners on the fly? Seems possible too, idk 🤔
it's common that there are events for key up, and key down, but they may share an event type such as KeyEvent.
If they share the same event type, but they have different payloads, then you would still need two classes for these 2 event payloads (or they are as primitive as int
, then okay 😄). So the advantage that we have here with eventpp is that you can listen for all KeyEvent
s at once no matter what payloads of these events are 😋 (it's still possible with my example after some small modifications. Using inheritance you can have a listener for KeyEvent
that will be called for every subclass of this type, e.g. struct KeyDown : KeyEvent {}
)
But you definitely have a point here:
Also it's not rare that many events don't need any data, defining a class for such event is overkill.
My solution requires a separate type for every event (such class can be defined in one line, but you're still right 😄)
And thank you for the example of making the same with eventpp. It looks almost identical and it's easier than I thought.
from eventpp.
In your approach, it's difficult to support multiple arguments in listener. What to do if the first argument is int
, and the second is T
?
eventpp is a general library, it needs to support all possible use cases, and as you can see, it doesn't enforce any limitations.
Also, if the default in eventpp is the generic approach, then you can't simulate the enumerator identifier solution. As you already swa, it's easy to simulate your generic approach in eventpp.
from eventpp.
Okay, I got it. Thank you for the explanation! 😀
from eventpp.
Related Issues (20)
- maybe a typo in argumentadapter.md document HOT 2
- Can you add an extra sample code for the Tutorials of EventDispatcher document HOT 10
- Clang compile error HOT 2
- [Question] Are event cbs, after a dispatch, processed async or sync? HOT 2
- Thread safety ? HOT 2
- Confusion about the parameters of the `eventpp::EventQueue.enqueue` HOT 1
- Run unittest failed HOT 4
- What is the difference between eventpp and libevent/libuv/libev HOT 1
- Dispatcher模板类型限定,如何适配任意的事件 HOT 1
- 如何实现不定参数调用? HOT 2
- New version release (vcpkg) HOT 3
- Function in CallbackList for removing all callbacks HOT 3
- Documentation for eventmaker is out of date HOT 1
- Compilation failed when using 'counterRemover' for the 'HeterEventDispatcher' of two function lists HOT 2
- Break on receiving false from callback/event dispatch? HOT 2
- Conan instructions HOT 5
- Remove Listener Example HOT 5
- shadowing error HOT 2
- Could EventQueue.add_listener be called in a thread other than the event processing thread? HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from eventpp.