Is it possible to use parameter pack instead of sequence of nested templates?

Viewed 65

Hy, I am crafting some meta-programming library that could help to construct complex objects from simple ad-mixture classes through the inheritance.

For instance I got some mechanisms those produce a set of template classes, each representing a single property.

I`ve came to a final construction procedure that looks like this:

class Car : public Position< Size< Color< BaseObj<Car> > > > {/*...*/};

and i quite don't like it.
(BaseObj is always the most inner template in a sequence)

I tried to make some processing template to be able to write it like this:

class Car : public Proc< Position, Size, Color, Car > {/*...*/};

but got no success.

Is it possible to make such a template?
Are there any other more readable semantics those could have the same effect as a sequence of such nested templates?

2 Answers

So, you want...

nest<A, B, C, D>::type<E>

...to become...

A<B<C<D<E>>>>

This is a job for recursion.


template <template <typename> typename...>
struct nest;

template <template <typename> typename First, 
          template <typename> typename... Rest>
struct nest<First, Rest...>
{
    template <typename Leaf>
    using type = First<typename nest<Rest...>::template type<Leaf>>;
};

template <template <typename> typename Last>
struct nest<Last>
{
    template <typename Leaf>
    using type = Last<Leaf>;
};

Usage example:

template <typename> struct A { };
template <typename> struct B { };
template <typename> struct C { };
template <typename> struct D { };
struct E { };

int main()
{
    static_assert(std::is_same_v<
        typename nest<A, B, C, D>::template type<E>,
        A<B<C<D<E>>>>
    >);
}

live example on wandbox.org

Edit It appears that I misunderstood the question. I thought you wanted to change your design to simply use a list of traits, rather than having traits nested recursively. I now understand you're simply looking for a drop-in replacement that allows you to write a list, that boils down to your old design. But that leaves the question: why do you really want to stick with that design? What purpose does it serve? I'm assuming the only reason it was like that, was that you weren't able to use variadic templates before.

I think my answer is still viable, but it requires changing your current implementation of Position, Size, Color, etc. I can't really suggest how until you provide a more clear description of what those things do.

Old answer:

Well, it would be a bit easier if you put the CRTP-argument in front.

template<class S, class... P>
class Proc : public P...
{
    // ...
};

class Car : public Proc<Car, Position, Size, Color> {/*...*/};
Related