jcai
jcai

Reputation: 3593

Obtain all-but-last parameter of variadic template

I have a ctor declared like this:

template<typename... Coords>
MyClass<T>(vector<T> values, Coords... coords) { /* code */ }

I want it to look like this:

template<typename... Coords>
MyClass<T>(Coords... coords, vector<T> values) { /* code */ }

but the standard requires the variadic argument to be the last. If I write something like

template<typename... Args>
MyClass<T>(Args... coordsThenValues) { /* code */ }

how would I split coordsThenValues into an all-but-last parameter pack Coords... coords and the last parameter vector<T> values?

Upvotes: 4

Views: 1169

Answers (1)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275405

Do you like tuples?

How do you like forward as tuple?

struct foo {
  template<class...Ts>
  foo(Ts&&...ts):
    foo(
      magic<0>{}, // sent it to the right ctor
      std::index_sequence< sizeof...(ts)-1 >{}, // the last shall be first
      std::make_index_sequence<sizeof...(ts)-1>{}, // the first shall be last
      std::forward_as_tuple(std::forward<Ts>(ts)...) // bundled args
    )
  {}
private:
  template<size_t>
  struct magic {};
  template<size_t...I0s, size_t...I1s, class...Ts>
  foo(
    magic<0>, // tag
    std::index_sequence<I0s...>, // first args
    std::index_sequence<I1s...>, // last args
    std::tuple<Ts...> args // all args
  ):
    foo(
      magic<1>{}, // dispatch to another tagged ctor
      std::get<I0s>(std::move(args))..., // get first args
      std::get<I1s>(std::move(args))... // and last args
    )
  {}
  // this ctor gets the args in an easier to understand order:
  template<class...Coords>
  foo(magic<1>, std::vector<T> values, Coords...coords) {
  }
};

here the public ctor packs up the arguments into a tuple of references (possibly l, possibly r). It also gets two sets of indexes.

It then sends it to magic<0> ctor, which shuffles the arguments around so that the last one is first (assuming the indexes are right).

The magic<1> ctor gets the vector first, then the coords.

Basically I shuffled the arguments around so the last one became first.

magic just exists to make me not have to think much about overload resolution, and make which ctor I'm forwarding to explicit. It would probably work without it, but I like tagging when I'm doing something crazy with ctor forwarding.

Upvotes: 6

Related Questions