There are four pair-like types in the standard, namely std::array
, std::pair
, std::tuple
, and ranges::subrange
, where the overload of std::get
for ranges::subrange
is defined in [range.subrange#access-10]:
template<size_t N, class I, class S, subrange_kind K> requires (N < 2) constexpr auto get(const subrange<I, S, K>& r); template<size_t N, class I, class S, subrange_kind K> requires (N < 2) constexpr auto get(subrange<I, S, K>&& r);
Effects: Equivalent to:
if constexpr (N == 0) return r.begin(); else return r.end();
And ranges::subrange::begin()
has two overloads:
constexpr I begin() const requires copyable<I>;
[[nodiscard]] constexpr I begin() requires (!copyable<I>);
I noticed that this std::get
only has two overloads, and there is no corresponding overload for non-const lvalue reference, which makes it impossible for us to apply std::get
to lvalue input_range
with non-copyable
iterator (godbolt):
#include <ranges>
#include <sstream>
int main() {
auto ints = std::istringstream{"42"};
auto is = std::ranges::istream_view<int>(ints);
std::ranges::input_range auto r = std::ranges::subrange(is);
auto b = r.begin(); // OK
auto b2 = std::get<0>(r); // Error, passing 'const subrange' as 'this' argument discards qualifiers
}
So why does std::get
only have two function overloads for ranges::subrange
? Does it miss the overloads for ranges::subrange&
and const ranges::subrange&&
? Is this a standard defect or is it intentional?