Skip to content

Instantly share code, notes, and snippets.

@Garciat
Created October 1, 2013 00:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Garciat/6772412 to your computer and use it in GitHub Desktop.
Save Garciat/6772412 to your computer and use it in GitHub Desktop.
#include <utility>
#include <typeinfo>
struct Base {
virtual int f() = 0;
};
struct Derived1 : public Base {
virtual int f() final override {
return 42;
}
};
struct Derived2 : public Base {
virtual int f() final override {
return 13;
}
};
template <typename T>
struct pmf_traits;
template <typename T, typename R, typename... Ps>
struct pmf_traits<R (T::*)(Ps...)> {
using self_type = R (T::*)(Ps...);
using class_type = T;
using result_type = R;
using func_type = R (Ps...);
};
// ^^ repeat for cv-qualifiers
template <typename TPMF, TPMF pmf, typename... Ds>
struct devirt_caller;
template <typename TPMF, TPMF pmf>
struct devirt_caller<TPMF, pmf> {
using T = typename pmf_traits<TPMF>::class_type;
using R = typename pmf_traits<TPMF>::result_type;
template <typename... Ps>
static R call(T& o, Ps&& ...params) {
return (o.*pmf)(std::forward<Ps>(params)...);
}
};
template <typename TPMF, TPMF pmf, typename D, typename... Ds>
struct devirt_caller<TPMF, pmf, D, Ds...> {
using T = typename pmf_traits<TPMF>::class_type;
using R = typename pmf_traits<TPMF>::result_type;
template <typename... Ps>
static R call(T& o, Ps&& ...params) {
if (typeid(o) == typeid(D)) {
auto ptr = static_cast<D*>(&o);
const auto rpmf = static_cast<R (D::*)(Ps...)>(pmf);
return (ptr->*rpmf)(std::forward<Ps>(params)...);
}
return devirt_caller<TPMF, pmf, Ds...>::call(o, std::forward<Ps>(params)...);
}
};
template <typename TPMF, TPMF pmf>
struct devirt {
template <typename... Ds>
using with = devirt_caller<TPMF, pmf, Ds...>;
};
#define make_devirt(a) devirt<decltype(a), a>
int test(Base& b) {
return make_devirt(&Base::f)::with<Derived1, Derived2>::call(b);
}
// Above should statically unfold to the following (but doesn't)
int test2(Base& b) {
if (typeid(b) == typeid(Derived1))
return static_cast<Derived1*>(&b)->f();
if (typeid(b) == typeid(Derived2))
return static_cast<Derived2*>(&b)->f();
return b.f();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment