5

Consider the following pseudo code :

template<class... T>
struct worker : unique<T...>::type...{};
struct x{};
struct y{};
struct z{};

Is it possible to write a template unique such that it generates a parameter pack consisting of only unique types among Ts, so that worker<x,y,x,z> will be directly derived from x, y, z respectively ,in that order, given Ts are non final classes?

user1436623
  • 73
  • 1
  • 4
  • What is the purpose of such a class? – Nawaz Jun 05 '12 at 07:14
  • @Nawaz If nothing else, in a non-recursive tuple implementation like that of libc++ , which just aggregates the variadic types as base classes, will eliminate the need for an extra intermediate base class, in that process and cut the code short by 200 lines. – user1436623 Jun 05 '12 at 08:18

2 Answers2

9

AFAIK: No.

The problem is that type is the result of a typedef directive, and typedef cannot alias packs. It is actually a bother, and most often computations on packs require introducing a wrapper type (such as template <typename...> struct pack {};) just to be able to pass them around.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 4
    @R.MartinhoFernandes: `std::tuple` is good when you want to instantiate the pack. But for just passing a list of types it's overkill and does not indicate the intent as precisely. It also requires one more include and taxes the compiler resources (it's a heavyweight template class). – Matthieu M. Jun 05 '12 at 07:58
  • I accept the answer with a sad face. My understanding is that parameter pack is not a type, so `typedef` is out of question. But an `using` directive to alias a parameter pack is what i was looking for. Passing variadic types or values via a `pack` is all ok, but delayed expanding them directly at all contexts where such expansion is allowed , like base-specifier-list or initializer-list or template-argument-list would have been great. – user1436623 Jun 05 '12 at 08:34
  • @user1436623: I agree, I also wish they could have been expanded in other places too (like class attributes). Maybe if we lobby the C++ guys hard enough we'll get it for next version :) – Matthieu M. Jun 05 '12 at 08:37
  • 3
    the more you go in depth in C++ compile time power, the more frustrated you become by its limitations. We are all losing our time investigating crazy ways to leverage metaprogramming but this is not what sells. This kind of fancy features are attractive to programmers but they are productivity traps. – v.oddou Mar 14 '15 at 03:27
4

Parameter packs cannot be easily stored, so I don't think what you want can be done. However, since you seem to need this feature in order to inherit from a set of bases, you can use some template metaprogramming to create a base type inheriting linearly from all the bases in your set. Before that, you can easily filter the duplicates from the parameter pack.

Here is an implementation of this approach using Boost.MPL:

#include <boost/mpl/fold.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/vector.hpp>

namespace mpl = boost::mpl;

template < typename ...Args >
struct inherit_uniquely
{
    // filter out duplicates
    typedef typename
        mpl::fold<
            mpl::vector< Args... >,
            mpl::set0<>,
            mpl::insert< mpl::_1, mpl::_2 >
        >::type unique_bases;

    // create base type
    typedef typename
        mpl::inherit_linearly<
            unique_bases,
            mpl::inherit< mpl::_1, mpl::_2 >
        >::type type;
};

template < typename ...Bases >
struct Derived : inherit_uniquely< Bases... >::type
{};

struct X { int x;};
struct Y { int y;};
struct Z { int z;};

int main()
{
    Derived< X, Y, Z > d;
    d.x = 1;
    d.y = 2;
    d.z = 3;

    X& d_as_x = d;
    Y& d_as_y = d;
    Z& d_as_z = d;
}
slashmais
  • 7,069
  • 9
  • 54
  • 80
Luc Touraille
  • 79,925
  • 15
  • 92
  • 137
  • Thanks for posting an alternative. This is something i am presently using. But inheriting indirectly sometime causes problem with the ability to detect the existence of a inherited member in the class. – user1436623 Jun 05 '12 at 08:22
  • What does `X & d_as_x = d;` mean? What is `d_as_x` here? And how can you use `&` with `X` which is a *type*, not *value*. Explain this part a bit. – Nawaz Jun 05 '12 at 08:40
  • 1
    @Nawaz what? `X&` is a reference to `X`. `d_as_x` is a reference to the subobject `X` of `d`. This needs no explanation in this context. – R. Martinho Fernandes Jun 05 '12 at 08:54
  • @R.MartinhoFernandes: Ohh... My God. – Nawaz Jun 05 '12 at 09:02
  • 2
    @Nawaz: We all have some brain malfunction once in a while :)! – Luc Touraille Jun 05 '12 at 12:26