Question

I'm trying to forward a series of parameters to two different mixin classes as follows:

template <typename... Checkers>
class Checker : public Checkers... {
public:
    template<typename... Args>
    Checker(Args&&... args) : Checkers(std::forward<Args>(args))... { }
};

template <typename... Handlers>
class Handler : public Handlers... {
public:
    template <typename... Args>
    Handler(Args&&... args) : Handlers(std::forward<Args>(args))... { }
};

template <typename C, typename H>
class Tester : public C, H {
public:
    template <typename... ArgC, typename... ArgH>
    Tester(std::tuple<ArgC...>&& argc, ArgH&&... argh) : C(argc), H(argh...) {
    }
};

Checker and Handler are two different collections of Mixin classes with different requirements for each but shared requirements for all members. I realize I can't do a double variadic construction in Tester (the compiler can't deduce where to split the arguments so passes them all to Handler and none to Checker) so I pass the Checker arguments in a Tuple and the Handler arguments in a variadic list. The problem is, Checker's constructor is responsible for forwarding those parameters to its bases. Handler can do it because Handler's constructor is a variadic list, but Checker gets a tuple but you can't for-each forward a tuple's elements like forward can a variadic parameter list.

Any advice would be greatly appreciated. Thanks.

Additional

A solution would be to either a) unpack argc into Checker's variadic constructor or b) Make Checker's constructor take a tuple and then somehow forward each element of that tuple to each of Checker's mixin bases, Checkers.... I realize std::pair has a trick for forwarding a tuple as a fixed argument list to it's types, such as a 3-parametered std::vector constructor using the std::piecewise_construct type marker to inform it to do the unpack, but I don't see how this can be applied here. I looked at GCC 4.8.1's implementation of std::pair with std::piecewise_construct and couldn't figure it out. I read some of the older, pre-C++11 books on template metaprogramming (Modern C++ Design and C++ Template Metaprogramming, for example) but I'm at a loss here now that there's a standard and I'm trying to avoid Boost and Loki.

Additional

Must conform to at least GCC 4.7.2. The solution I found based on std::pair requires Constructor Inheritance, which didn't become available until GCC 4.8.1 which isn't supported on my build system.

Additional

Although GCC 4.6.3 support would be nice, Delegated Constructors were added in 4.7.2 so I should have access to that language feature.

Was it helpful?

Solution

http://cpptruths.blogspot.fr/2012/06/perfect-forwarding-of-parameter-groups.html

Davidbrcz's solution as specified in his blog above was sufficient to solve my conundrum. The solution is rather complex so I'll direct you to his page for it, but the basic idea is to on-the-fly create a numeric index tuple, à la std::maketuple(0, 1, 2, ...) where the tuple contains each of the indices of the various members of the tuple you need to enumerate. Then you just use:

M(std::forward<ArgM>(std::get<IdxM>(argm))...)

For M as either C or H in the example above and ArgM the arguments to M and IdxM the equally sized tuple of indices. Because the lists are the same length, the list gets rolled out into parameters in tandem and the tuple is unpacked.

The limitation is because you want the complicated step of building the index tuple to be hidden as an implementation detail, you need to use Constructor Delegation such that the public constructor takes the 2 tuples which then delegates to the private constructor which takes 2 value tuples and 2 index tuples. GCC 4.7.2 supports Delegated Constructors, but 4.6.3 doesn't.

To get around this, you need to make the 4-parameter constructor (2 tuples of values, 2 tuples of indices) public and then I wrote a macro to fill in the index tuple parameters:

#if __GNUC__ < 4 || __GNUC_MINOR__ <= 6
#define ZEROPARAM , detail::make_indices<>::type()
#define ONEPARAM , detail::make_indices<int>::type()
#define TWOPARAM , detail::make_indices<int, int>::type()
#define THREEPARAM , detail::make_indices<int, int, int>::type()
#define FOURPARAM , detail::make_indices<int, int, int, int>::type()
#define FIVEPARAM , detail::make_indices<int, int, int, int, int>::type()
#define SIXPARAM , detail::make_indices<int, int, int, int, int, int>::type()
#define SEVENPARAM , detail::make_indices<int, int, int, int, int, int, int>::type()
#define EIGHTPARAM , detail::make_indices<int, int, int, int, int, int, int, int>::type()
#define NINEPARAM , detail::make_indices<int, int, int, int, int, int, int, int, int>::type()
#define TENPARAM , detail::make_indices<int, int, int, int, int, int, int, int, int, int>::type()
#else // __GNUC__ < 4 || __GNUC_MINOR__ <= 6
#define ZEROPARAM
#define ONEPARAM
#define TWOPARAM
#define THREEPARAM
#define FOURPARAM
#define FIVEPARAM
#define SIXPARAM
#define SEVENPARAM
#define EIGHTPARAM
#define NINEPARAM
#define TENPARAM
#endif // __GNUC__ < 4 || __GNUC_MINOR__ <= 6

And then add the appropriate macro following the construction of the given Tester, at least while there are still folks on GCC 4.6.3 while I work to get everyone to at least 4.7.2 and preferable 4.8.1. :)

I wish I could give Davidbrcz credit for the solution but at least this may be helpful for folks facing a similar problem to apply his solution in their specific case. The main thing is copy his make_indices template class to do the actual work; the rest is a cake walk!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top