Search code examples
c++c++11variadic-templates

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?


Solution

  • 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.