0ax1
0ax1

Reputation: 505

specific class in inheritance hierachy as type in boost::signal2 callback

I'm using a boost::signals2::signal inside a gui-class like this:

class GuiElement {
    //...
    typedef boost::signals2::signal<void(GuiElement &)> GuiElementSignal;
    virtual GuiElementSignal &getSignal() { return signal_; };
}

All gui-classes inherit from this class so that callbacks can be registered. An example with a Toggle class:

toggle.getSignal().connect([](lx::GuiElement &el) {
    // cast to access toggle specific functions
    state = static_cast<lx::Toggle &>(el).state();
    cout << state << endl;
});

Inside the callback function everytime I have to cast GuiElement to a SpecificClass to access the specific class functions. I'd like to avoid this cast and declare the callback signature as: toggle.getSignal().connect([](lx::Toggle &el) {...

Is there a way to realize this with templates with something like typedef boost::signals2::signal<void(T &)> GuiElementSignal where T is replaced with the class?

Upvotes: 0

Views: 238

Answers (2)

jav
jav

Reputation: 674

If you don't want to expose signal_ and don't want that all your gui-classes have to use the connect() function, you could register all your callback functions as slots. E.g. (using signals2) :

#include <iostream>
#include <boost/signals2/signal.hpp>
#include <boost/bind.hpp>
#include <boost/optional/optional_io.hpp>

#define registerEvent_(A)   registerEvent(boost::bind(A, this, _1, _2))

struct A
{
    typedef boost::signals2::signal<int (int &, int &)> EventSignal;
    typedef EventSignal::slot_type SlotType;

    void registerEvent(const SlotType & slot);
    void triggerAll(int& a1, int& a2);

    EventSignal signal_;
};

void A::registerEvent(const SlotType & slot) { signal_.connect(slot); }
void A::triggerAll(int& a1, int& a2) {std::cout << signal_(a1, a2) << "\n";}

struct B : public A
{
    B();
    int myFunc(int& a1, int& a2);
};

B::B() {
#ifdef WITHMACRO
    registerEvent_(&B::myFunc);
#else
    registerEvent(boost::bind(&B::myFunc, this, _1, _2));
#endif
}
int B::myFunc(int& a1, int& a2) { return a1 + a2 + 1; }

int main()
{
    int a1 = 2;
    int a2 = 3;
    B b;
    b.triggerAll(a1, a2);
}

Note: And you could use a macro (WITHMACRO) if you even want to hide the bind.

Upvotes: 0

Tam&#225;s Szelei
Tam&#225;s Szelei

Reputation: 23971

You can use the curiously recurring template pattern to solve this problem, for example:

template<typename T>
class GuiElement {
    //...
    typedef boost::signals2::signal<void(T&)> GuiElementSignal;
    virtual GuiElementSignal &getSignal() { return signal_; };
};

class Button : public GuiElement<Button> {/* ... */};

Upvotes: 1

Related Questions