c++ - How to implement static virtual member function -
tl/dr: there (more convenient) way implement such functionality?
i have invoke same static code both class-type , class-instance represented reference base:
int main() { // invokes on class bar<c1>(); // invokes c1::foo() bar<c2>(); // invokes c2::foo() // invokes on instance bar(c1()); // invokes c1::foo() bar(c2()); // invokes c2::foo() }
but problem can't implement without code duplication. each derived class have write both static , virtual methods. static - because can't invoke virtual method on class, , virtual, calls static - because there's no way distinguish object behaviour except virtual methods:
template<typename t> void bar() { t::foo(); } void bar(a const &r) { r.foo(); }
thus, workaround solve problem of duplicating code:
#include <iostream> class { public: virtual void foo() const = 0; }; template<typename derived_t> class b: public { public: virtual void foo() const { derived_t::foo(); } }; class c1 : public b<c1> { public: static void foo() { std::cout << "c1::foo()" << std::endl; } }; class c2 : public b<c2> { public: static void foo() { std::cout << "c2::foo()" << std::endl; } };
this approach works perfectly, has @ least 2 inconveniences.
firstly, had introduce auxiliary template class b implemented virtual method.
secondly, every inheritance chain (from b final class) must consists of templates makes impossible using intermediate class pointer/reference type. eg. <- b <- t1 <- t2 <- c , t1 , t2 must template classes provide c::foo().
one possible solution crtp base class injection.
template <typename t, typename... bases> struct crtpfooinjector : bases... { virtual void vfoo() { t::foo(); } };
this injector template. implements virtual version of foo, nothing else.
struct base: crtpfooinjector<base> { static int foo() { std::cout << "base::foo()" << std::endl; } }; struct der1 : crtpfooinjector<der1, base> { static int foo() { std::cout << "der1::foo()" << std::endl; } }; struct der2 : crtpfooinjector<der2, base> { static int foo() { std::cout << "der2::foo()" << std::endl; } }; struct der12 : crtpfooinjector<der12, der1, der2> { static int foo() { std::cout << "der12::foo()" << std::endl; } };
now instead of normal hierarchy base <- der1 <- der12
have different 1 injector <- base <- injector <- der1 <- injector <- der12
, should transparent users.
if need mix in virtual base classes:
template <typename t> struct virtual : virtual t { }; struct der1 : crtpfooinjector<der1, virtual<base>> ...
Comments
Post a Comment