How to unpack std::tuple from C++ template?
Asked Answered
R

2

7

I have a class that is expected to take std::tuple of certain types (arbitrary count is allowed) as a template argument. I want to declare a tuple of vectors of the types. For instance, I have

template <typename T>
class MyClass {/*...*/}

I instantiate it

MyClass<std::tuple<int, bool>> my_class;

and I aim to create a field like this

std::tuple<std::vector<int>, std::vector<bool>> my_tuple;

I know that if I had a class definition

template <typename... T>
class MyClass2 {/*...*/}

I could instantiate it by passing the data types without a tuple

MyClass<int, bool> my_class2;

and then simply create the field

std::tuple<std::vector<int>, std::vector<bool>> my_tuple2;

using

std::tuple<std::vector<T>...> my_tuple2;

Hence, I was thinking that I should somehow unpack the data types from the tuple. Is it possible?

Rummy answered 16/4, 2020 at 23:13 Comment(0)
T
4

Yes, and to add to cigien's answer, another way to go about it would be to unpack it through a template specialization.

template<typename Tuple>
class MyClass;

template<typename... Ts>
class MyClass<std::tuple<Ts...>>
{
    // ...
    using VectorTuple = std::tuple<std::vector<Ts>...>;
    // ...
};
Takao answered 17/4, 2020 at 0:58 Comment(1)
Nice. This is an elegant solution. +1Euphrosyne
E
4

Sure, you just need another level of indirection (as usual):

// this function declaration is used just for the type
// transformation, and needs no definition
template <typename... Types>
auto unpack(std::tuple<Types...>) -> std::tuple<std::vector<Types>...> ;

template <typename Tuple>
class MyClass
{
  // use the return type of unpack
  decltype(unpack(std::declval<Tuple>())) my_tuple; 
};

And now you can instantiate MyClass with a tuple, like this:

MyClass<std::tuple<int, double>> m;

which contains a field my_tuple of type

std::tuple<std::vector<int>, std::vector<double>>

Here's a working demo.

Euphrosyne answered 16/4, 2020 at 23:22 Comment(1)
I am going to accept Travis's answer, since I found it slightly more elegant. However, thank you very much too.Rummy
T
4

Yes, and to add to cigien's answer, another way to go about it would be to unpack it through a template specialization.

template<typename Tuple>
class MyClass;

template<typename... Ts>
class MyClass<std::tuple<Ts...>>
{
    // ...
    using VectorTuple = std::tuple<std::vector<Ts>...>;
    // ...
};
Takao answered 17/4, 2020 at 0:58 Comment(1)
Nice. This is an elegant solution. +1Euphrosyne

© 2022 - 2024 — McMap. All rights reserved.