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?