#include #include extern volatile int poop; struct A { virtual void f() { poop += 10; } }; struct B : public A { virtual void f() { poop += 20; } }; struct C : public A { virtual void f() { poop += 30; } }; struct D final : public B { virtual void f() final { poop += 40; } }; template struct pmf_traits; template struct pmf_traits { using arg_type = A; }; template struct devirt_help; template struct devirt_help { template devirt_help(K &&obj, F &f, Fs... fs) { using T = typename pmf_traits::arg_type; if (typeid(obj) == typeid(T)) { f(static_cast(obj)); } else { devirt_help(obj, fs...); } } }; template struct devirt_help { template devirt_help(K &&obj, F f) { f(obj); } }; template void devirt(T &&obj, Fs&&... funcs) { devirt_help(obj, funcs...); } void hello(A &a) { devirt(a, [](D &o) { o.D::f(); } , [](C &o) { o.C::f(); } , [](A &o) { o.f(); }); }