Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Slicing a vector of tuples into a tuple of std::optional

I’m having trouble slicing a tuple.

I want to output a tuple with std::optional, so that if the vectors 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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading