HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Views and ranges for tuple-like objects

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
objectslikeviewsrangestupleforand

Problem

This interesting idea came up when I was designing the for_each for tuple-like objects in this post. The for_each in that post makes it possible to write code like:

auto t = std::make_tuple(42, 'c', 3.14);
for_each(t, [](auto x) { std::cout << x << '\n'; });


But unfortunately, this way we can only iterate over the entire tuple-like object, unlike std::for_each, which, by accepting iterators, enables us to iterate over only a part of a collection. If only we could achieve something similar for tuple-likes!

I guess theoretically it is possible to create some kind of heterogeneous iterator, but that feels kind of weird, because iterator types usually inherit from std::iterator for some fixed T.

So I think for tuple-like objects, a good way is to create some kind of ranges or views into the original objects, specified by indices. A range is a tuple of appropriate types of references to consecutive elements in the original tuple and preserves element order. A view is a tuple of appropriate types of references to possibly non-consecutive elements in the original tuple and does not necessarily preserve element order. Examples (pseudo-code):

(lvalue) std::tuple:
    range  : std::tuple<>
    range  : std::tuple
    range  : std::tuple
    view   : std::tuple
    view: std::tuple

(rvalue) std::tuple:
    range: std::tuple
    view    : std::tuple

(lvalue) std::tuple:
    range: std::tuple

...


Then, we will be able to do something like:

auto t = std::make_tuple(42, 'c', 3.14);

for_each(make_tuple_range(t), [](auto x) { std::cout (t), [](auto x) { std::cout (t), [](auto& x) { x += 1; });
for_each(t, [](auto x) { std::cout << x << ' '; });
// prints: 42 d 4.14


Enough examples. Time for implementation (C++14):

```
#include
#include

namespace detail {

template
constexpr auto make_tuple_range_impl(std::index_sequence,
Tuple&& t) noexcept
{
return std::forward_as_tuple(
std::get(

Solution

My 2 cents:

I think you should restructure your code so that a range is simply a contiguous index_sequence; and taking a subtuple by range is simply taking those elements corresponding to the index sequence. So you would implement a make_index_range which is similar to std::make_index_sequence, and then using that range you would have something like

template 
constexpr auto subtuple(F f, Tuple t, std::index_sequence) {
    return std::make_tuple(std::get>(t)...);
}


(there may need to be forwarding in there, I'm not sure.)

Code Snippets

template <class F, Tuple t, size_t... Is>
constexpr auto subtuple(F f, Tuple t, std::index_sequence<Is...>) {
    return std::make_tuple(std::get<std::integral_constant<size_t, Is>>(t)...);
}

Context

StackExchange Code Review Q#134856, answer score: 2

Revisions (0)

No revisions yet.