Giter Site home page Giter Site logo

Comments (4)

wqking avatar wqking commented on June 5, 2024

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.

KyrietS avatar KyrietS commented on June 5, 2024

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 KeyEvents 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.

wqking avatar wqking commented on June 5, 2024

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.

KyrietS avatar KyrietS commented on June 5, 2024

Okay, I got it. Thank you for the explanation! 😀

from eventpp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.