Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

subrange get<0> requires a copyable iterator #2425

Merged
merged 2 commits into from
Jan 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -3487,7 +3487,7 @@ namespace ranges {

// clang-format off
template <size_t _Idx, class _It, class _Se, subrange_kind _Ki>
requires (_Idx < 2)
requires ((_Idx == 0 && copyable<_It>) || _Idx == 1)
_NODISCARD constexpr auto get(const subrange<_It, _Se, _Ki>& _Val) {
if constexpr (_Idx == 0) {
return _Val.begin();
Expand Down
44 changes: 43 additions & 1 deletion tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
// Covers ranges::view_interface and ranges::subrange

#include <cassert>
#include <concepts>
#include <forward_list>
#include <istream>
#include <list>
#include <ranges>
#include <string_view>
Expand All @@ -24,6 +24,7 @@ using std::output_iterator_tag, std::input_iterator_tag, std::forward_iterator_t
int main() {} // COMPILE-ONLY

void test_LWG_3470() {
// LWG-3470 relaxed the "convertible-to-non-slicing" requirements to allow this non-slicing case
int a[] = {1, 2, 3};
int* b[] = {&a[2], &a[0], &a[1]};
[[maybe_unused]] auto c = std::ranges::subrange<const int* const*>(b);
Expand Down Expand Up @@ -1483,3 +1484,44 @@ namespace test_subrange {
STATIC_ASSERT(test_tuple<subrange<int*, std::unreachable_sentinel_t, subrange_kind::sized>>());
STATIC_ASSERT(test_tuple<subrange<int*, std::unreachable_sentinel_t, subrange_kind::unsized>>());
} // namespace test_subrange

namespace test_lwg_3589 {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"LWG" is capitalized on 26.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can live with this, no need to reset testing.

// LWG-3589 added a Constraint to std::get<0>(const subrange&) to require the iterator type to be copyable
template <class T, size_t I>
concept CanGet = requires {
std::get<I>(std::declval<T>());
};

template <class T, size_t I>
concept CanRangesGet = requires {
ranges::get<I>(std::declval<T>());
};

template <class I, class S>
constexpr bool test() {
using ranges::subrange;

STATIC_ASSERT(std::input_iterator<I>);
STATIC_ASSERT(std::sentinel_for<S, I>);

STATIC_ASSERT(CanGet<const subrange<I, S>&, 0> == std::copyable<I>);
STATIC_ASSERT(CanGet<const subrange<I, S>&, 1>);
STATIC_ASSERT(!CanGet<const subrange<I, S>&, 2>);
STATIC_ASSERT(CanGet<subrange<I, S>, 0>);
STATIC_ASSERT(CanGet<subrange<I, S>, 1>);
STATIC_ASSERT(!CanGet<subrange<I, S>, 2>);

STATIC_ASSERT(CanRangesGet<const subrange<I, S>&, 0> == std::copyable<I>);
STATIC_ASSERT(CanRangesGet<const subrange<I, S>&, 1>);
STATIC_ASSERT(!CanRangesGet<const subrange<I, S>&, 2>);
STATIC_ASSERT(CanRangesGet<subrange<I, S>, 0>);
STATIC_ASSERT(CanRangesGet<subrange<I, S>, 1>);
STATIC_ASSERT(!CanRangesGet<subrange<I, S>, 2>);

return true;
}

// Validate with a copyable iterator type, and with a move-only iterator type
STATIC_ASSERT(test<int*, int*>());
STATIC_ASSERT(test<ranges::iterator_t<ranges::istream_view<int>>, ranges::sentinel_t<ranges::istream_view<int>>>());
} // namespace test_lwg_3589