2

How to define a class MultiInherit<MyTuple<X1,X2,...>> to inherit from X1,X2,... ?
I want to pass MyTuple<X1,X2,...> around to compose a new object type.

template <class... Xs> class MyTuple{};
template <class MyTupleXs> class MultiInherit : public All_Xs_in_MyTupleXs { //??

};

Here is its usage and MCVE (uncompilable):-

class B{public: int b;};
class C{public: int c;};
class BC : public MultiInherit<MyTuple<B,C>> {
    public: void testCompile(){
        this->b=this->c;   
    }
};
int main(){
}

Attempt 1

Below is the closest to what I wanted.
If I get raw-types (e.g. B,C) as template argumant rather than MyTuple<B,C>, it would be easy :-
(MCVE, compilable)

template <class... Xs> class MultiInherit : public Xs... { 
};
class B{public: int b;};
class C{public: int c;};
class BC : public MultiInherit<B,C> {
    public: void testCompile(){
        this->b=this->c;   
    }
};  

Reference: Variadic templates and multiple inheritance in c++11
This doesn't solve. I want to pass an encapsulated type MyTuple<B,C>, not the B,C.

Attempt 2

I thought about adding a new variadic typedef MyXs in MyTuple:-

template <class... Xs> class MyTuple{
   public: using MyXs=Xs...;    
};
template <class MyTupleXs> class MultiInherit : public MyTupleXs::MyXs { 
};

Nevertheless, it seems to me that the language has no such feature.

(I am new to variadic template.)

javaLover
  • 6,347
  • 2
  • 22
  • 67

1 Answers1

5

Simple answer

You have to create a template specialization of MultiInherit. Let's look at the base case of MultiInherit:

template<class... Xs> 
class MultiInherit : public Xs... {
    // Stuff
}; 

Here, we take a bunch of types and inherit from them. But we can use a template specialization to unpack tuples:

// Specialization on MyTuple
template<class... Xs> 
class MultiInherit<MyTuple<Xs...>> : public Xs... {
     // Stuff
};

This allows you to do what you want. Given a MyTuple, you have a MultiInherit class that inherits from all the members.

More general case

Defining a type list. If you want to do things more generally, it'll be useful to do them based on templates representing type lists. We can define a template to represent a type list:

template<class...>
struct TypeList {}; 

Concatenating type lists. We can define more templates to concatenate type lists. ConcatLists is a function that takes two type lists, and returns a TypeList that concatenates them:

template<class... Xs, class... Ys>
TypeList<Xs..., Ys...> ConcatLists(TypeList<Xs...>, TypeList<Ys...>) {
    return {}; 
}

We can use that to define a concat_t that does that automatically:

template<class TypeListA, class TypeListB>
using concat_t = decltype(ConcatLists(TypeListA{}, TypeListB{})); 

Substituting MultiInherit for TypeList. We can also substitute one type for another type using template specializations.

// Base case
template<template<class...> class Replacement, class List>
struct SubstituteList;

template<
    template<class...> class Replacement, 
    template<class...> class Original,
    class... Xs>
struct SubstituteList<Replacement, Original<Xs...>> {
    using type = Replacement<Xs...>;
};

template<template<class...> class Replacement, class List>
using substitute_list_t = typename SubstituteList<Replacement, List>::type; 

This means that you can take a TypeList and replace it with a MultiInherit:

template<class ListOfTypes>
using MultiInheritFromTypeList = substitute_list_t<MultiInherit, ListOfTypes>; 

Example usage. If you want to convert a TypeList to a MultiInherit:

using T1 = TypeList<int, char, bool>;
// T2 is MultiInherit<int, char, bool>;
using T2 = MultiInheritFromTypeList<T1>;

Example with concat. Or, if you want to concat multiple TypeLists and convert it to a MultiInherit:

using T1 = TypeList<int, char, bool>;
using T2 = TypeList<double, float>;
// T3 is MuliInherit<int, char, bool, double, float>
using T3 = MultiInheritFromTypeList<concat_t<T1, T2>>;
Alecto Irene Perez
  • 10,321
  • 23
  • 46