简体   繁体   中英

Is there a better way to return the same string literal from both a static and non-static function?

My c++ is pretty rusty and generics always confuse me anyway, so the combination is not good for my brain, so here is my problem.

I have a set of classes that are all going to look like this:

class MyEvent2 : public Event 
{

    public:
    static constexpr char* CLASS_NAME = "MyEvent2";
    MyEvent2(Object& sender) :  Event(sender)
    {
    }

    virtual ~MyEvent2() {}

    static const char* EventId() {
        return MyEvent2::CLASS_NAME;
    }

    const char* eventId() override {
        return MyEvent2::CLASS_NAME;
    }
};

The classes will be used to register event handlers on an event bus, so I add the handlers like so.

  EventBus::AddHandler<MyEvent>(*this);  
  EventBus::AddHandler<MyEvent2>(*this);  

then I create intances of the events and fire them like this:

MyEvent e1(*this);
MyEvent2 e2(*this);
EventBus::FireEvent(e1);
EventBus::FireEvent(e2);

My question is how do I make this generic? I would like to be able to make some derived "Event" class where I just need to include the one line that really needs to be unique

static constexpr char* CLASS_NAME = "TheClassName";

btw: I know could use typeid to get something like this, but I can't use it on Arduino devices.

and then add unique "Event" specific fields and members.

Here is what I have done so far:

I created a template class (or should it be called a class template?):

template<class T>
class ArduinoEvent : public Event 
{

    public:
    T(Object& sender) :  Event(sender)
    {
    }

    virtual ~T() {}

    static const char* EventId() {
        return T::CLASS_NAME;
    }

    const char* eventId() override {
        return T::CLASS_NAME;
    }
};

But I am not sure how to use this or if this is even the right direction.

You could try with Curiosly Recurring Pattern (CRTP) . It would look something like following :

template <typename  T>
class BaseEvent : public Event {
    public:
        static constexpr const char* id = T::CLASS_NAME;

        constexpr const char* eventId() const {
            return T::CLASS_NAME;
        }
};

The template would then be used to instantiate new event classes as follows:

class MyEvent1 : public BaseEvent<MyEvent1> {
    public:
        static constexpr const char* CLASS_NAME = "MyEvent1";
};

class MyEvent2 : public BaseEvent<MyEvent2> {
    public:
        static constexpr const char* CLASS_NAME = "MyEvent2";
};

You could then use these classes as expected:

int main() {

    MyEvent1 e1;
    cout << e1.eventId() 
         << ", " 
         << MyEvent1::id
         << endl;

    MyEvent2 e2;
    cout << e2.eventId() 
         << ", "
         << MyEvent2::id
         << endl;
    return 0;
}

You can check that eventId() behaves as expected in this online example ). Note that the template BaseEvent needs to inherit from Event if you want to handle all events in a polymorphic way.

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