I have a boost::mpl::vector
containing several types, e.g.
typedef boost::mpl::vector<T1, T2, T3, T4> list_type;
For some known types T1, T2, T3, T4
. Is there any way to use metaprogramming to transform this list into a type that represents direct linear inheritance, in the order of the types in the vector? I would like to synthesize a type that has the behavior that would be consistent with this:
struct T1 { };
struct T2 : T1 { };
struct T3 : T2 { };
struct T4 : T3 { };
struct synthesized_type : T4 { };
There is boost::mpl::inherit_linearly
that gives me similar behavior, but not exactly what I want. The type that results from using that behaves more like:
struct synthesized_type : T1, T2, T3, T4 { };
which behaves differently in some cases. For instance, say you have a function that is overloaded on some subset of the types T1, T2, T3, T4
:
void foo(T1) { }
void foo(T3) { }
foo(synthesized_type()); // I would like to be able to do this
With the first (desired) hierarchy that I gave above, there are no ambiguities in overload resolution; I can pass synthesized_type
to foo()
and it will invoke foo(T3)
, because T3
is the most derived type in the ancestry of synthesized_type
.
In the case where I use boost::mpl::inherit_linearly
, however, this results in a compiler error due to ambiguity in overload resolution, because there is no priority specified between the parent types; the compiler can't choose between foo(T1)
and foo(T3)
.
Is there any way to get the effect that I want? Stated more formally:
Given a list of types, I would like to use metaprogramming to synthesize some type that has the properties of the first hierarchy I described above (namely, that the synthesized type is implicitly convertible to each type
T1, T2, T3, T4
, with priority in that order, soT4
is preferred toT3
, which is preferred toT2
, and so on). Is this possible?
If your types are all CRTP types you can do this sorcery:
#include <iostream>
template< template<class> class... Ts >
struct TVec { };
struct EmptyClass { };
template< class T >
struct Inheritor;
template< template<template<class> class> class U, template<class> class T>
struct Inheritor< U<T> >
: public T<EmptyClass> { };
template< template<template<class> class...> class U, template<class> class T, template<class> class... Ts>
struct Inheritor< U<T, Ts... > >
: public T<Inheritor< U<Ts...> > > { } ;
template< typename Base >
struct T1
: public Base { };
template< typename Base >
struct T2
: public Base { };
template< typename Base >
struct T3
: public Base { };
template<typename X>
void foo(T1<X> t) {
std::cout << "T1" << std::endl;
}
template<typename X>
void foo(T2<X> t) {
std::cout << "T2" << std::endl;
}
template<typename X>
void foo(T3<X> t) {
std::cout << "T3" << std::endl;
}
int main() {
using Types = TVec< T1, T2, T3 >;
using Types2 = TVec< T3, T2, T1 >;
using Derived = Inheritor<Types>;
using Derived2 = Inheritor<Types2>;
//Inheritor<TVec< T1, T2, T3>> x;
Derived x;
Derived2 x2;
foo(x); // T1 overload
foo(x2); // T3 overload
}
You can't get that exact behavior, since it would involve redefining T1, T2... Is this close enough?
template< class T >
struct Inheritor { };
template< class T, template<class> class U >
struct Inheritor< U<T> >
: public T { };
template< template<class...> class U, class T, class... Ts >
struct Inheritor< U<T, Ts...> >
: public T
, public Inheritor< U< Ts... > > { };