I'm having trouble slicing a tuple
.
I want to output a tuple
with std::optional
, so that if the vector
s are of an uneven length, the tuple is padded with empty std::optional
objects.
An example of my implementation is below, but I'm running into a roadblock, which is commented in the if-statements
template <typename... Types>
auto sliceTuple(std::tuple<std::vector<Types>...> &data, int index)
{
std::tuple<std::optional<Types>...> output;
std::apply(
[&output, index](auto &vector)
{
if (index < vector.size())
{
//Problem here: How would I write vector[index] to the tuple?
}
else
{
//Problem here: How would I write an empty std::optional to the tuple?
}
},
data)
return (output);
}
If std::apply
had a compile-time index, it would be trivial, (I could just use std::get<i>(output);
) but as far as I know, it does not. Is there a way to implement this "slice tuple of vectors" function, and if so, how would I do so?
An example of what I want to do:
Starting with a tuple of 3 vectors:
<[1, 2], [3, 4, 5], [6, 7, 8]>
should become
<1, 3, 6> when index = 0
<2, 4, 7> when index = 1
<empty std::optional, 5, 8> when index = 2
CodePudding user response:
template <typename... Types>
auto sliceTuple(std::tuple<std::vector<Types>...>& data, size_t index)
{
return std::apply([index](const auto&... vs) {
return std::make_tuple([index](const auto& v) {
if (index < std::size(v))
{
return std::make_optional(v[index]);
}
return std::optional<Types>{};
}(vs)...);
}, data);
}
https://godbolt.org/z/T68YPxcsY
Here is version which is spitted into two parts:
- apply tuple on lambda which constructs tuple of optionals
- take index based optional from a range
template <typename R>
auto optional_from_range(const R& r, size_t index) -> std::optional<std::decay_t<decltype(r[index])>>
{
if (index < std::size(r)) {
return r[index];
}
return {};
}
template <typename... Types>
auto sliceTuple(std::tuple<std::vector<Types>...>& data, size_t index)
{
return std::apply([index](const auto&... vs) {
return std::make_tuple(optional_from_range(vs, index)...);
}, data);
}
https://godbolt.org/z/z7xrbr4d3
this should be easier to understand.
CodePudding user response:
With the help of std::apply
and the fold-expression:
#include <optional>
#include <tuple>
#include <vector>
template <typename... Types>
auto sliceTuple(std::tuple<std::vector<Types>...>& data, int index) {
return std::apply([index](auto&... vecs) {
return std::tuple(
(index < vecs.size() ? std::optional(vecs[index]) :
std::nullopt)...);
}, data);
}