0

I have Consequence, Event and EventsConsequences classes. Each Event's derived class has the list of Consequence objects that it triggers stored in EventsConsequences object. If two Event objects are of the same type (class) then they must trigger the same Consequences.

So in EventsConsequences class I have:

unordered_map<std::type_index, std::vector<Consequence*>> consequences;

template<typename Event>
void add_trigger_of(Consequence *consequence) {
    consequences[typeid(Event)].push_back(consequence);
}

template<typename Event>
void trigger_consequences_of(Event *event) {
    for (Consequence *consequence : consequences[typeid(Event)]);
        consequence->react_to(event);
}

In Event class:

EventsConsequences* consequences;

void trigger() {
    consequences->trigger_consequences_of(this);
}

And, of course, I have many derived classes of both Event and Consequence.

What I want is for it to work, but it doesn't. It always calls

EventsConsequences::trigger_consequences_of<Event>(Event*)

But not of a derived classes.

The only idea I have to fix this is to make Event::trigger() virtual and for every derived class override it

void DerivedEvent::trigger() override {
    consequences->trigger_consequences_of(this);
}

But I hate writing WET code. Are there any other ways of doing it?

4
  • 2
    So, you want to achieve polymorphism ("What I want is func() to be dependent on class type") but don't want to use the built-in tools for doing polymorphism? Commented Oct 31, 2017 at 16:31
  • Why are you trying to make a virtual function (dynamic polymorphism) call a template (static polymorphism)? Do you actually gain anything from having the template be separate? Does it do anything different for the different types? If yes, why can't you just put that different stuff directly in the virtual function implementations, not in the template? You should probably describe what you're trying to do, not how you're currently trying to do it, as this may well be an x/y question. Commented Oct 31, 2017 at 16:33
  • @underscore_d Edited my question. Commented Oct 31, 2017 at 17:30
  • IMO if you have to use typeid() then it's usually an indication that your design could use a rethink. I don't immediately have a replacement to suggest, though. Commented Oct 31, 2017 at 17:32

2 Answers 2

3

Use the curiously recurring template pattern (CRTP):

template <typename Derived>
struct Base {
    void foo() {
        func(static_cast<Derived*>(this));
    }
};

struct A : Base<A> { };
struct B : Base<B> { };

int main() {
    A a;
    B b;
    a.foo();
    b.foo();
}
Sign up to request clarification or add additional context in comments.

1 Comment

Note: the question looked considerably different when I wrote that answer.
2

You should use the type_index of the dynamic type of the object rather than the type_index of the type template argument to access the map.

consequences[typeid(*event)]

Just make sure that Event has at least one virtual function.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.