3

How can I get access to the individual items in a parameter pack?

Given the following:

template<typename T>
struct X {};

template<class R, class... Args>
struct X<R (Args...)>
{
  // how can I create a typedef for the first parameter
  // basically I want to do something like if arg1 exists typedef it
  // pseduo code below

  if (Args[0])
   typedef typename Args[0] Parameter1
}

Otherwise I might have to do something like this but was hoping to keep it generic

template<class R, class... Args>
struct X<R (Arg1, Args...)>
{

}
bjackfly
  • 3,236
  • 2
  • 25
  • 38
  • Are other members of `X` going to use this `typedef`? How? If `Args` is empty, do you want the `typedef` to not exist, or to be `void`? – Casey Jan 16 '14 at 16:26

2 Answers2

7

Getting the first item in the param pack is pretty easy with a helper:

template <typename T, typename... Ts>
using first_type = T;

However this of course will fail to compile if your parameter pack is empty. What kind of behaviour do you expect when your pack is empty? Do you just not want the typedef to exist? In that case, just partially specialize your struct X for the empty parameter pack case.

bstamour
  • 7,746
  • 1
  • 26
  • 39
5

You can use std::tuple_element:

template<typename... Args>
struct arg
{
    template<int N>
    using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
};

template<typename R, typename... Args>
struct X<R (Args...)>
{
    using first = typename arg<Args...>::template type<0>;
};

That will allow you to access an arbitrary type through a compile-time index. You can also use static_assert to assert at compile-time that a parameter pack has at least one element.

template<typename... Args>
struct has_first_arg : std::true_type { };

template<>
struct has_first_arg<> : std::false_type { };

template<typename R, typename... Args>
struct X<R (Args...)>
{
    static_assert(has_first_arg<Args...>::value,
                  "Parameter pack must have at least one element");
};
David G
  • 94,763
  • 41
  • 167
  • 253
  • the line `arg::type<0>` will NOT compile; you need `template` keyword here : `arg::template type<0>` ;-) – Nawaz Jan 16 '14 at 16:10
  • @Nawaz I'm still working on it. In the meanwhile, can you explain why? :) – David G Jan 16 '14 at 16:12
  • you need template keyword here : `arg::template type<0>` . :-) – Nawaz Jan 16 '14 at 16:12
  • seems the using command should be `using type = typename std::tuple_element >::type;` Thanks for this solution! – bjackfly Jan 16 '14 at 16:48
  • Is there a way to make it work for both zero argument and one argument where it would set the first = void type since we don't care when we have no arguments – bjackfly Jan 16 '14 at 17:37
  • @bjackfly You can create a class template which is specialized for "" and have a typedef equal to "T". Then you create another specialization for the class which has an empty parameter pack "<>" The typedef in that case will be a null class type (for example, a class named "null"). – David G Jan 16 '14 at 17:55
  • Yeah this is what I did I was wondering if I could have done it without an extra specialization which causes most of the methods to be copied as is, but it is working and probably more clear this way – bjackfly Jan 17 '14 at 16:53
  • @bjackfly You can't do it without an extra specialization if you want to return a `typedef NullType type` for the empty case. And what do you mean by "[it] causes most of the methods to be copied as is"? – David G Jan 17 '14 at 16:58