21

I'm currently struggling with the following code, the intent of which is to implement variadic variadic template templates:

template
<
  template <typename... HeadArgs> class Head,
  template <typename... TailArgs> class...
>
struct join<Head<typename HeadArgs...>, Head<typename TailArgs...>...>
{
  typedef Head<typename HeadArgs..., typename TailArgs......> result;
};

Ideally, I'd be able to use this template metafunction to achieve the following:

template <typename...> struct obj1 {};
template <typename...> struct obj2 {};

typedef join
<
  obj1<int, int, double>, 
  obj1<double, char>,
  obj1<char*, int, double, const char*>
>::result new_obj1;

typedef join
<
  obj2<int, int, double>, 
  obj2<double, char>,
  obj2<char*, int, double, const char*>
>::result new_obj2;

/* This should result in an error, because there are 
   different encapsulating objects
typedef join
<
  obj1<int, int, double>, 
  obj1<double, char>,
  obj2<char*, int, double, const char*>
>::result new_obj;
*/

The output of the above would hopefully create new_obj1 and new_obj2 in the form template<int, int, double, double, char, char*, int, double, const char*> struct new_obj[1|2] {};

I'm using gcc 4.6.2 on Windows, which outputs an "expected parameter pack before '...'" for the expansion of "Head<typename TailArgs...>...".

This error is reproducable with gcc 4.5.1.

kmore
  • 924
  • 9
  • 18
  • 2
    The argument *name* inside the `template` specification of the template template argument is optional and entirely cosmetic; it's not actually available as a real parameter. – Kerrek SB Mar 12 '12 at 06:33
  • @KerrekSB is there any way to get the parameters of a template template parameter? – kmore Mar 12 '12 at 06:43
  • I edited my post; I was missing the variadic case. In answer to your question: Yes, by supplying an explicit template parameter (pack) and matching. – Kerrek SB Mar 12 '12 at 06:53
  • 3
    @kmore No, because once you provide parameters to a template, it's no longer a template. `template_name< parameters >` is a class and will match a plain `class` or `typename` template parameter. – Potatoswatter Mar 12 '12 at 06:54
  • Indeed. You should notice that `join` isn't actually matching *templates*, but *types*. So the templates are just a detail of the specialization, not a defining characteristic of `join`. – Kerrek SB Mar 12 '12 at 06:59
  • @KerrekSB That clarification simplifies everything for me, and makes it possible to create another version without the restriction that all objects be the same type by adding `template class Tpl2` to the parameter list. Actually, the real key seems to be simplifying this to a manageable specialization (`join, Tpl>`) rather than an impossible generic (`join...>`). – kmore Mar 12 '12 at 07:09
  • there is no such thing as a "template template". some people get confused by the term "template template parameter" and think that there are some parameters that are "template templates". What that term actually means is that there are some template parameters that are templates. – Johannes Schaub - litb Mar 12 '12 at 19:38
  • @kmore, `join...>` does not exist as you point out correctly and as KarrekSB showed, there is an easy workaround in this case. However, there are many cases where the workaround is much harder. I am [lobbying (see here)](http://codereview.stackexchange.com/q/33147/31160) for an extension to support `join...>` and `template` and related syntax. – Patrick Fromberg Oct 25 '13 at 03:07

1 Answers1

23

Try something like this:

template <typename...> struct join;

template <template <typename...> class Tpl,
          typename ...Args1,
          typename ...Args2>
struct join<Tpl<Args1...>, Tpl<Args2...>>
{
    typedef Tpl<Args1..., Args2...> type;
};

template <template <typename...> class Tpl,
          typename ...Args1,
          typename ...Args2,
          typename ...Tail>
struct join<Tpl<Args1...>, Tpl<Args2...>, Tail...>
{
     typedef typename join<Tpl<Args1..., Args2...>, Tail...>::type type;
};
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • That's a perfect solution when combining the parameters of two objects. However, I'm looking to combine the parameters of a variable number of objects. I tried [modifying](http://ideone.com/njBuE) your answer, but there's still an error with the expansion pack. **EDIT: you beat me to it, thank you!** – kmore Mar 12 '12 at 06:54