Tuple view element types

I am creating a utility to create a view in an object similar to a tuple. The goal is to include code like this:

// make_tuple_view<Is...>(t): view of t elements at positions Is...

auto t = std::make_tuple(42, 'c', 3.14);
auto tv = make_tuple_view<2, 1, 0, 1>(t);  // tv == (3.14, 'c', 42, 3.14)
++std::get<0>(tv);
// tv == (4.14, 'c', 42, 4.14)
// t  == (42, 'c', 4.14)

Thus, the types of tuple elements are the corresponding types of links to the corresponding elements of the original tuple. I am currently listing reference types:

#include <tuple>
#include <utility>

namespace detail {

template<std::size_t FromIndex, std::size_t... Is, typename Tuple>
constexpr auto make_tuple_range_impl(std::index_sequence<Is...>,
                                     Tuple&& t) noexcept
{
    return std::forward_as_tuple(
            std::get<FromIndex + Is>(std::forward<Tuple>(t))...);
}

}  // namespace detail

// make_tuple_range
template<std::size_t FromIndex, std::size_t ToIndex, typename Tuple>
constexpr auto make_tuple_range(Tuple&& t) noexcept
{
    static_assert(FromIndex <= ToIndex,
                  "FromIndex must be less than or equal to ToIndex");

    return detail::make_tuple_range_impl<FromIndex>(
            std::make_index_sequence<ToIndex - FromIndex>(),
            std::forward<Tuple>(t));
}

// make_tuple_view
template<std::size_t... Is, typename Tuple>
constexpr auto make_tuple_view(Tuple&& t) noexcept
{
    return std::forward_as_tuple(std::get<Is>(std::forward<Tuple>(t))...);
}

Tests :

double pi = 3.14;
std::tuple<int, double&, const char, float> t(42, pi, 'c', 0);

// non-const lvalue
static_assert(std::is_same<
                  decltype(make_tuple_range<0, 3>(t)),
                  std::tuple<int&, double&, const char&>
              >::value, "");

// const lvalue
const auto& ct = t;
static_assert(std::is_same<
                  decltype(make_tuple_view<3, 0, 2, 1>(ct)),
                  std::tuple<const float&, const int&, const char&, double&>
              >::value, "");

// non-const rvalue
static_assert(std::is_same<
                  decltype(make_tuple_range<1, 4>(std::move(t))),
                  std::tuple<double&, const char&&, float&&>
              >::value, "");

// const rvalue
const auto&& crt = std::move(t);
static_assert(std::is_same<
                  decltype(make_tuple_range<1, 4>(std::move(crt))),
                  std::tuple<double&, const char&, const float&>
              >::value, "");

However, I am not completely sure of my implementation. Is there any extreme case where invalid reference types can be inferred?

: , TIL ! , , make_tuple_view/range . , , . , make_tuple_view/range .

+4
2
namespace details {
  template<std::size_t...Is,class TupleIn>
  auto tuple_view( std::index_sequence<Is...>, TupleIn&& tin) {
    return std::forward_as_tuple( std::get<Is>(std::forward<TupleIn>(tin))... );
  }
}
template<class TupleIn>
auto tuple_view(TupleIn&& tin) {
  auto indexes = std::make_index_sequence< std::tuple_size<std::remove_reference_t<TupleIn>>{} >;
  return details::tuple_view( indexes, std::forward<TupleIn>(tin) );
}

?

:

template<std::size_t I>
using index_t = std::integral_constant< std::size_t, I >;
template<std::size_t I>
constexpr index_t<I> index{};

template<std::size_t...Is>
auto unpack_indexes( std::index_sequence<Is...> ) {
  return [](auto&& f) {
    return decltype(f)(f)( index<Is>... );
  };
}
template<std::size_t N>
auto unpack_indexes( index_t<N> ) {
  return unpack_indexes( std::make_index_sequence<N>{} );
};

template<class TupleIn>
auto tuple_view(TupleIn&& tin) {
  auto size = std::tuple_size<std::remove_reference_t<TupleIn>>{};
  auto indexes = unpack_indexes(size);
  return indexes(
    [&](auto...Is) {
      return std::forward_as_tuple( std::get<Is>(std::forward<TupleIn>(tin))... );
    }
  );
}

() , details.

.

+6

. std::tie .

#include <tuple>
#include <iostream>


template<class Tuple, std::size_t...Is>
auto tuple_view(Tuple&& t, std::index_sequence<Is...>)
{
    return std::tie(std::get<Is>(std::forward<Tuple>(t))...);
}

int main()
{
    auto a = std::make_tuple(1,2,3);

    auto b = tuple_view(a, std::index_sequence<0,1,2,1,0>());

    std::cout << std::get<0>(b) << std::endl;
    std::cout << std::get<1>(b) << std::endl;
    std::cout << std::get<2>(b) << std::endl;
    std::cout << std::get<3>(b) << std::endl;
    std::cout << std::get<4>(b) << std::endl;
}

:

1
2
3
2
1
+3

All Articles