6
6
#include < forward_list>
7
7
#include < ranges>
8
8
#include < span>
9
+ #include < sstream>
10
+ #include < string>
9
11
#include < type_traits>
10
12
#include < utility>
11
13
#include < vector>
@@ -464,8 +466,9 @@ template <ranges::input_range Rng, class Expected>
464
466
constexpr bool test_input (Rng&& rng, Expected&& expected) {
465
467
using ranges::chunk_view, ranges::equal, ranges::iterator_t , ranges::sentinel_t ;
466
468
467
- using V = views::all_t <Rng>;
468
- using R = chunk_view<V>;
469
+ using V = views::all_t <Rng>;
470
+ using BI = iterator_t <V>;
471
+ using R = chunk_view<V>;
469
472
470
473
same_as<R> auto r = chunk_view{forward<Rng>(rng), 2 };
471
474
auto outer_iter = r.begin ();
@@ -478,6 +481,19 @@ constexpr bool test_input(Rng&& rng, Expected&& expected) {
478
481
479
482
auto inner_iter = val_ty.begin ();
480
483
same_as<default_sentinel_t > auto inner_sen = val_ty.end ();
484
+
485
+ { // Check iter_move (other tests are defined in 'test_lwg3851' function)
486
+ same_as<ranges::range_rvalue_reference_t <Rng>> decltype (auto ) rval = iter_move (as_const (inner_iter));
487
+ assert (rval == expected[0 ][0 ]);
488
+ STATIC_ASSERT (noexcept (iter_move (inner_iter)) == noexcept (ranges::iter_move (declval<const BI&>())));
489
+ }
490
+
491
+ if constexpr (indirectly_swappable<BI>) { // Check iter_swap (other tests are defined in 'test_lwg3851' function)
492
+ STATIC_ASSERT (is_void_v<decltype (iter_swap (as_const (inner_iter), as_const (inner_iter)))>);
493
+ STATIC_ASSERT (noexcept (iter_swap (inner_iter, inner_iter))
494
+ == noexcept (ranges::iter_swap (declval<const BI&>(), declval<const BI&>())));
495
+ }
496
+
481
497
assert (inner_iter != inner_sen);
482
498
if constexpr (sized_sentinel_for<sentinel_t <Rng>, iterator_t <Rng>>) {
483
499
assert (inner_sen - inner_iter == 2 );
@@ -579,6 +595,38 @@ using move_only_view = test::range<Category, const int, test::Sized{is_random},
579
595
IsCommon, test::CanCompare{derived_from<Category, forward_iterator_tag>},
580
596
test::ProxyRef{!derived_from<Category, contiguous_iterator_tag>}, test::CanView::yes, test::Copyability::move_only>;
581
597
598
+ // Check LWG-3851: 'chunk_view::inner-iterator missing custom iter_move and iter_swap'
599
+ void test_lwg3851 () {
600
+ { // Check 'iter_move'
601
+ istringstream ints{" 0 1 2 3 4" };
602
+ auto v = views::istream<int >(ints) | views::chunk (2 );
603
+ auto o = v.begin ();
604
+ auto c = *o;
605
+ auto i = c.begin ();
606
+
607
+ same_as<int &&> decltype (auto ) rval = iter_move (i);
608
+ assert (rval == 0 );
609
+ }
610
+
611
+ { // Check 'iter_swap'
612
+ istringstream ints1{" 0 1 2 3 4" };
613
+ auto v1 = views::istream<int >(ints1) | views::chunk (2 );
614
+ auto o1 = v1.begin ();
615
+ auto c1 = *o1;
616
+ auto i1 = c1.begin ();
617
+
618
+ istringstream ints2{" 5 6 7 8 9" };
619
+ auto v2 = views::istream<int >(ints2) | views::chunk (2 );
620
+ auto o2 = v2.begin ();
621
+ auto c2 = *o2;
622
+ auto i2 = c2.begin ();
623
+
624
+ iter_swap (as_const (i1), as_const (i2));
625
+ assert (*i1 == 5 );
626
+ assert (*i2 == 0 );
627
+ }
628
+ }
629
+
582
630
int main () {
583
631
{ // Validate views
584
632
// ... copyable
@@ -617,4 +665,6 @@ int main() {
617
665
618
666
STATIC_ASSERT ((instantiation_test (), true ));
619
667
instantiation_test ();
668
+
669
+ test_lwg3851 ();
620
670
}
0 commit comments