Is there a tricky way to avoid overriding all pure virtual functions of template base class, used in multiple inheritance

StackOverflow https://stackoverflow.com/questions/22347201

Question

Pretty complicated (and bad) title, here's what I mean by example:

struct type1 {};
struct type2 {};
struct type3 {};

template< typename TYPE >
struct interface {
    virtual void f( TYPE ) = 0;
};

struct processor {
    template< typename TYPE >
    void f( TYPE ) {
        // something + for some TYPE-s have specializations, but it's irrelevant
    }
};

struct der: interface< type1 >, interface< type2 >, interface< type3 > {
    processor p;

    void f( type1 t ){ p.f( t ); }
    void f( type2 t ){ p.f( t ); }
    void f( type3 t ){ p.f( t ); }
};

Is there any tricky way to avoid all overrides in der? In the real case, der inherits interface 10 times (with different template types and it could be extended in the future). And it's rather ugly to have 10+ overrides of f when their bodies are the same.

processor could be changed to anything, also der::p could be some container, holding a template-d processor, etc.

It sounds like I want to have a virtual template member function f, which is not allowed.

I thought about using a macro, but I don't like that idea.

EDIT Note: can't use c++11, unfortunately. And can't change typeN types, which are not in hierarchy.

Was it helpful?

Solution

C++03 solutions

(See KerrekSB's answer for solutions using C++11 features)

You can use another layer of inheritance and CRTP to dispatch the calls to your processor:

template< typename TYPE, class ProcessorHolder >
struct processorDispatch : interface<TYPE> {
    virtual void f( TYPE t ) override {
        processor& p = static_cast<ProcessorHolder*>(this)->p; //CRTP --> explicit downcast
        p.f(t);
    }
};

And use it as

struct der: processorDispatch< type1,der >, processorDispatch< type2,der >, processorDispatch< type3,der > {
    processor p;

  //make f visible - either
    using processorDispatch< type1,der >::f;
    using processorDispatch< type2,der >::f;
    using processorDispatch< type3,der >::f;
  //or
    template <typename TYPE>
    void f(TYPE t) {
      processorDispatch<TYPE, der>::f(t);
    }
}

};

A take at Kerrek's non-CRTP-solution, but "C++11-free" vía base class chaining:

struct der_base {
  processor p;
};

template <class TYPE, class Base = der_base>
struct der_t : Base, interface<TYPE> {
  void f(TYPE t) { this->p.f(t); } 
  using Base::f;
};

template <class TYPE>
struct der_t<TYPE, der_base> : der_base, interface<TYPE> {
  void f(TYPE t) { this->p.f(t); } 
};

And then use

typedef der_t<type1, der_t<type2, der_t<type3> > > der;

OTHER TIPS

You could make der a template:

template <typename ...> struct der;

template <> struct der<>
{
    processor p;
};

template <typename Base, typename ...Rest>
struct der<Base, Rest...> : der<Rest...>, interface<Base> 
{ 
    void f(Base x) { this->p.f(x); }
};

Then use:

der<type1, type2, type3> d;

Here's an alternative design using CRTP:

template <typename Actual, typename Base> struct FImpl : Base
{
    void f(Base x) { static_cast<Actual*>(this)->p.f(x); }
};

template <typename ...T> struct der : FImpl<der, T>...
{
    processor p;
};

Another solution, similar to @ArneMertz 's one, could be (but it involves several instances of processor - one per type, so could be inappropriate for some cases):

struct type1 {};
struct type2 {};
struct type3 {};

template< typename TYPE >
struct interface 
{
    virtual void f( TYPE ) = 0;
};

template< typename TYPE >
struct processor 
{
    void f( TYPE t ){ std::cout << typeid( t ).name() << std::endl; }
};

template< typename TYPE >
struct interface_impl: interface< TYPE >
{
    processor< TYPE > p_;
    void f( TYPE t )
    {
        p_.f( t );
    }
};

struct final: interface_impl< type1 >, interface_impl< type2 >, interface_impl< type3 >
{
    template< typename TYPE >
    void f( TYPE t )
    {
        interface_impl< TYPE >::f( t );
    }
};

This is almost the same, with one difference only - processor is added in the "middle" class. In terms of @Arne's answer:

  • make processor template class
  • processorDispatch has a member processor with the same TYPE

This:

  • eliminates the static_cast
  • simplifies the inheritance (one type vs two)

Or even processor could be defined inside interface_impl, like

template< typename TYPE >
struct interface_impl: interface< TYPE >
{
    struct processor 
    {
        void f( TYPE t ){ std::cout << typeid( t ).name(); }
    } p_;

    void f( TYPE t )
    {
        p_.f( t );
    }
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top