Assuming I have struct
and std::tuple
with same type layout:
struct MyStruct { int i; bool b; double d; }
using MyTuple = std::tuple<int,bool,double>;
Is there any standartized way to cast one to another?
P.S. I know that trivial memory copying can do the trick, but it is alignment and implementation dependent
You use a struct for things that meaningfully belong together to form a whole. You use a tuple for things that are together coincidentally. You can use a tuple spontaneously in your code.
Structs are similar to tuples, discussed in “The Tuple Type” section, in that both hold multiple related values. Like tuples, the pieces of a struct can be different types.
The new std::array and std::tuple containers provide developers with additional ways to manage structured data efficiently.
Class template std::tuple is a fixed-size collection of heterogeneous values. It is a generalization of std::pair.
We can use structured bindings to convert a struct into a tuple with a bit of work.
Struct-to-tuple is very awkward.
template<std::size_t N>
struct to_tuple_t;
template<>
struct to_tuple_t<3> {
template<class S>
auto operator()(S&& s)const {
auto[e0,e1,e2]=std::forward<S>(s);
return std::make_tuple(e0, e1, e2);
}
};
Now, write a to_tuple_t
for each size you want to support. This gets tedious. Sadly I know of no way to introduce a parameter pack there.
template<std::size_t N, class S>
auto to_tuple(S&& s) {
return to_tuple_t<N>{}(std::forward<S>(s));
}
I know of no way to calculate the value of N
required either. So you'd have to type the 3
in auto t = to_tuple<3>(my_struct);
when you call it.
I am not a master of structured bindings. There is probably a &&
or &
or a decltype that would permit perfect forwarding on these lines:
auto[e0,e1,e2]=std::forward<S>(s);
return std::make_tuple(e0, e1, e2);
but without a compiler to play with, I'll be conservative and make redundant copies.
Converting a tuple into a struct is easy:
template<class S, std::size_t...Is, class Tup>
S to_struct( std::index_sequence<Is...>, Tup&& tup ) {
using std::get;
return {get<Is>(std::forward<Tup>(tup))...};
}
template<class S, class Tup>
S to_struct( Tup&&tup ) {
using T=std::remove_reference_t<Tup>;
return to_struct(
std::make_index_sequence<std::tuple_size<T>{}>{},
std::forward<Tup>(tup)
);
}
SFINAE support based off tuple_size
might be good for to_struct
.
The above code works with all tuple-likes, like std::pair
, std::array
, and anything you custom-code to support structured bindings (tuple_size
and get<I>
).
Amusingly,
std::array<int, 3> arr{1,2,3};
auto t = to_tuple<3>(arr);
works and returns a tuple with 3 elements, as to_tuple
is based on structured bindings, which work with tuple-likes as input.
to_array
is another possibility in this family.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With