简体   繁体   中英

Event System with Template class deriving from Non-Template base class in c++

What I'm doing

I'm working on an event system. Basically there are "slots" which any member can chime into. All they need is an event name which it will be listening to, and a function. Since all the slots are stored I had to store them as a variable in a class.

The Problem

The function becomes unavailable when it's placed into the SlotBase class. I am wondering if there is a way to retain the function in the Slot class while storing in in the SlotBase class.

The Code

class SlotBase { };
//              TC - Template Class
//                              TA - Template Arguments (types)
template <class TC, typename ...TA>
class Slot : public SlotBase  {
public:
    Slot(TC* funcClass, void(TC::*func)(TA...)) {
        SetSlot(funcClass, func);
    }
    template <int ...Is>
    void SetSlot(TC* funcClass, void(TC::*func)(TA...), int_sequence<Is...>) {
        function = std::bind(func, funcClass, placeholder_temp<Is>{}...);
    }
    void SetSlot(TC* funcClass, void(TC::*func)(TA...)) {
        SetSlot(funcClass, func, make_int_sequence<sizeof...(TA)>{});
    }
    std::function<void(TA...)> returnFunction(){
        return function;
    }
private:
    std::function<void(TA...)> function;
};


//...


class RandomClass {
public:
    void randomFunction(int a, float b, int c){ //do stuff };
}


//...


RandomClass randC;
SlotBase baseS;

Slot newSlot(&randC, &RandomClass::randomFunction);
baseS = newSlot;


//...
//Later on down the line when an event was found matching slot call slot function


baseS.returnFunction()(//Correct arguments go here - leaving this out (a lot more code));

I didn't include the code for the integer sequences in the 'std::bind' as it isn't related to the problem.

What I have tried

I know that if I use a Slot cast on the baseS variable that would give me the result but I am unable to do so because I don't know the templates that Slot will have.

I have seen many similar posts stating to make baseS a pointer (such as here ) but I still don't understand how you would grab the function.

I think you need to start to accept that at some point if you want to use polymorph objects, you will need to create a virtual function in SlotBase . If you want to cast back to your type at creation before using the function, the polymorphism makes no sense, because you have carried the original type somewhere along with you to be able to do so, so why upcast anyway in the first time ?

If you really need to upcast, then you need to think about a RUNTIME solution to get back to access the derived functionality. In this case, this would mean you need to create a generic interface to your signals, so try to make a pure virtual method in SlotBase that will pack an undefined number of arguments, and implement that generic caller in your Slot so that it unpacks the arguments in order and calls your slot with the arguments. I don't know if variadic methods can be overriden though, that seems dubious. Otherwise you'll have to use boost::any or something to pack the arguments in a runtime collection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM