Signals & slots in Juce

I had a go at extending the system to handle static events as well.

It makes sense to use separate code; they can eventually be merged -- that will be trivial.

http://coliru.stacked-crooked.com/a/e0631620e8637786

Not quite sure what qualifies as the best Interface -- I've provided the following:

    event.addStaticHandler(&handler);
    event.fire(1);
    event.removeStaticHandler(&handler);
    
    // or...
    uint64_t id_A = event.addStaticHandler(&handler);
    event.fire(2);
    event.removeStaticHandler(id_A);
    
    // or...
    event += &handler;
    event.fire(3);
    event -= &handler;

Interestingly,  you can also pass a lambda, so the following also works:

    uint64_t id_L = event.addStaticHandler( [](int x){ ... } );
    event.fire(4);
    event.removeStaticHandler(id_L);

You can even cut it right down:

event += [] (int x) { ... }; 
event.fire(5);

The only problem is there is no way to remove that last one from event's subscriber list. I can imagine cases where this wouldn't be a problem, and it is very succinct!

π

PS Lambdas can capture, although I have no idea what happens if you add a lambda from inside some instance method that captures `this`, and then destroy the instance.

PPS I had tried to get the id to be the raw function pointer, but my technique for extracting this from a std::function seems to cause a segfault if I feed in a lambda.

PPPS complete listing:

// C++11 Static Event System
// π 10.03.2016
// 1st revision

#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <functional>

using namespace std;

template<class... Args>
class Event
{
private:
    using F = std::function<void(Args...)>;
    
    struct Invoker {
        F fp;
        uint64_t id;
    };
    
    std::vector<Invoker> staticInvokers;
    
    static void* getAddress(F f) {
        return (void*)*f.template target<void(*)(Args...)>();
    }
    
    uint64_t counter = 0;
    
public:
    void fire(Args... args) {
        for (auto& i : staticInvokers)  i.fp(args...);
    }

    uint64_t addStaticHandler(F f) {
        staticInvokers.push_back(Invoker{f,counter});
        return counter++; //getAddress(f);
    }
    
    void operator+=(F f) {
        addStaticHandler(f);
    }

    void removeStaticHandler(F f) {
        removeStaticHandler( getAddress(f) );
    }

    void operator-=(F f) {
        removeStaticHandler(f);
    }

void removeStaticHandler(void* addr) {
        auto to_remove = std::remove_if(
            staticInvokers.begin(),
            staticInvokers.end(),
            [addr](auto& item) { return Event::getAddress(item.fp) == addr; }
            );
        staticInvokers.erase(to_remove, staticInvokers.end()); // yup std::remove_if doesn't actually do the removing (gah)
    }
    
    void removeStaticHandler(uint64_t id) {
        auto to_remove = std::remove_if(
            staticInvokers.begin(),
            staticInvokers.end(),
            [id](auto& item) { return item.id == id; }
            );
        staticInvokers.erase(to_remove, staticInvokers.end()); // yup std::remove_if doesn't actually do the removing (gah)
    }
    
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

static void handler(int x) {
    cout << "handler hit with value: " << x << endl;
}

int main() {
    Event<int> event;
    
    event.addStaticHandler(&handler);
    event.fire(1);
    event.removeStaticHandler(&handler);
    
    // or...
    uint64_t id_A = event.addStaticHandler(&handler);
    event.fire(2);
    event.removeStaticHandler(id_A);
    
    // or...
    event += &handler;
    event.fire(3);
    event -= &handler;

    uint64_t id_L = event.addStaticHandler(
        [] (int x) {
            cout << "lambda hit with value: " << x << endl;
            }
        );
    event.fire(4);
    event.removeStaticHandler(id_L);

    event += [] (int x) { cout << "second lambda hit with value: " << x << endl; };
    event.fire(5);

    return 0;
}