0

Consider:

#include <vector>
#include <memory>

class Base {};
class Derived : public Base {};

template<typename T>
class Effect
{
public:
    virtual void call(T& val) = 0;
    // Additional Functions...
};

class BaseEffect : public Effect<Base>
{
public:
    // Since Derived inherits from Base, we are able to pass Derived to BaseEffect
    void call(Base& val) override { /*Code modifying Base*/ }
};

class DerivedEffect : public Effect<Derived>
{
public:
    void call(Derived& val) override { /*Code modifying Derived*/ }
};

int main()
{
    std::vector<std::unique_ptr<Effect<Derived>>> effects;
    effects.emplace_back(std::make_unique<DerivedEffect>());
    // Ugly and maybe undefined?
    effects.emplace_back(reinterpret_cast<Effect<Derived>*>(new BaseEffect()));

    Derived state;
    effects[0]->call(state); // Executes DerivedEffect::call
    effects[1]->call(state); // Executes BaseEffect::call
    return 0;
}

I know that effects will never store the template-argument; They will only ever access it through function calls. But I can't use std::function since the Effect-class is more complicated than just having one function. Also, I don't want to use dynamic_cast in Effect::call, since it will be executed a lot.

So is my question is, is the reinterpret-cast safe, under my previous assumptions? Additionally, is there a cleaner way to achieve my goal, apart from creating a custom container that manages the vector?

Djeurissen
  • 377
  • 5
  • 15
  • Which function do you expect `effects[1]->call` to be? – Daniel Dec 05 '20 at 11:33
  • 3
    [A `reinterpret_cast` has very few well-defined (but implementation-defined) meanings, and everything else is undefined.](https://en.cppreference.com/w/cpp/language/reinterpret_cast) Reinterpret-Casting across unrelated sibling classes as you do is *completely* undefined, and reinterpret-casting inside a class hierarchy simply never makes sense. If you don’t want the overhead of a `dynamic_cast`, use a `static_cast`. If that doesn’t work, the cast inside the class hierarchy is illegal. – Konrad Rudolph Dec 05 '20 at 11:39
  • 3
    `BaseEffect` is not `Effect`, using the pointer after the cast is UB. – rustyx Dec 05 '20 at 11:42
  • Yeah Im aware that every instance of Effect is an unrelated hierachy. Then it seems like casting is my only option. @Dani I made it a little bit clearer – Djeurissen Dec 05 '20 at 11:44
  • 1
    Why are you worrying about the performance of dynamic cast while using virtual functions? They are the same. Reinterpret cast is strongly undefined, it won't help you here. If you need the type information, do not erase it. All C++ calls are resolved at compile-time w.r.t to the parameters, so the last two lines have to know the left-side type to know which methods are available. Seems to me like X Y problem. – Quimby Dec 05 '20 at 11:50
  • As the other comments already said a reinterpret_cast is UB here. Practically it might work because both classes have the same memory layout. But if the compiler does de-virtualization it could call a different method. "UB" becomes usually a problem with the optimizers. – Bernd Dec 05 '20 at 15:40

0 Answers0