#include <typeinfo>
#include <typeindex>
#include <unordered_map>
struct Command { virtual ~Command() {}; };
struct SpecificCommandA: Command {};
struct SpecificCommandB: Command {};
struct SpecificCommandC: Command {};
struct Base {
virtual ~Base() {};
virtual void modify_command(Command &c, std::type_index); // default
void modify_command(Command &c) {
modify_command(c, std::type_index(typeid(c)));
}
};
template<typename Der, typename SpecC> struct Modifier {
static void execute(Der &d, Command &c) {
d.modify_command(static_cast<SpecC &>(c));
}
};
struct Derived: Base {
using Base::modify_command;
virtual void modify_command(SpecificCommandB &); // overload & override
void modify_command(Command &c, std::type_index ti) override {
using callable = void (*)(Derived &, Command &);
const static std::unordered_map<std::type_index, callable> derived_map =
{
{ std::type_index(typeid(SpecificCommandB)), Modifier<Derived, SpecificCommandB>::execute }
};
auto find_result = derived_map.find(ti);
if(derived_map.end() == find_result) { Base::modify_command(c, ti); }
else { (*find_result->second)(*this, c); }
}
};
struct DerivedOfDerived: Derived {
using Derived::modify_command;
virtual void modify_command(SpecificCommandB &); // overload & override
virtual void modify_command(SpecificCommandC &);
void modify_command(Command &c, std::type_index ti) override {
using callable = void (*)(DerivedOfDerived &, Command &);
const static std::unordered_map<std::type_index, callable> derived_map =
{
{ std::type_index(typeid(SpecificCommandB)), Modifier<DerivedOfDerived, SpecificCommandB>::execute },
{ std::type_index(typeid(SpecificCommandC)), Modifier<DerivedOfDerived, SpecificCommandC>::execute }
};
auto find_result = derived_map.find(ti);
if(derived_map.end() == find_result) { Derived::modify_command(c, ti); }
else { (*find_result->second)(*this, c); }
}
};
#include <iostream>
void Base::modify_command(Command &, std::type_index) { std::cout << "Default" << std::endl; }
void Derived::modify_command(SpecificCommandB &) { std::cout << "B in Derived" << std::endl; }
void DerivedOfDerived::modify_command(SpecificCommandB &) { std::cout << "B in DerivedOfDerived" << std::endl; }
void DerivedOfDerived::modify_command(SpecificCommandC &) { std::cout << "C" << std::endl; }
int main(int argc, const char *argv[]) {
SpecificCommandA a;
SpecificCommandB b;
Derived d;
d.modify_command(a);
d.modify_command(static_cast<Command &>(b));
d.modify_command(b);
DerivedOfDerived dod;
SpecificCommandC c;
dod.modify_command(a);
dod.modify_command(b);
dod.modify_command(c);
return 0;
}