From d4c3384aed02a36f1f11951ee8c6f8a3a208fd6d Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 23 Apr 2021 12:18:08 +0200 Subject: [PATCH 1/4] [ranges] Apply resolution of LWG3502 to elements_view fixes #1685 --- stl/inc/ranges | 18 ++++++++++++++++-- .../std/tests/P0896R4_views_elements/test.cpp | 9 +++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 08e1bfc39a5..739e6e55905 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -3701,10 +3701,14 @@ namespace ranges { // clang-format on }; + template + concept _Returnable_element = is_reference_v<_Tuple> || move_constructible>; + // clang-format off template requires view<_Vw> && _Has_tuple_element, _Index> && _Has_tuple_element>, _Index> + && _Returnable_element, _Index> class elements_view : public view_interface> { // clang-format on private: @@ -3768,7 +3772,12 @@ namespace ranges { _NODISCARD constexpr decltype(auto) operator*() const noexcept(noexcept(_STD get<_Index>(*_Current))) /* strengthened */ { - return _STD get<_Index>(*_Current); + if constexpr (is_reference_v>) { + return _STD get<_Index>(*_Current); + } else { + using _ElemTy = remove_cv_t>>; + return static_cast<_ElemTy>(_STD get<_Index>(*_Current)); + } } constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ { @@ -3835,7 +3844,12 @@ namespace ranges { #if _ITERATOR_DEBUG_LEVEL != 0 _Verify_offset(_Idx); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return _STD get<_Index>(*(_Current + _Idx)); + if constexpr (is_reference_v>) { + return _STD get<_Index>(*(_Current + _Idx)); + } else { + using _ElemTy = remove_cv_t>>; + return static_cast<_ElemTy>(_STD get<_Index>(*(_Current + _Idx))); + } } _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( diff --git a/tests/std/tests/P0896R4_views_elements/test.cpp b/tests/std/tests/P0896R4_views_elements/test.cpp index 82c58fae699..8484144dc2d 100644 --- a/tests/std/tests/P0896R4_views_elements/test.cpp +++ b/tests/std/tests/P0896R4_views_elements/test.cpp @@ -414,4 +414,13 @@ int main() { STATIC_ASSERT(test_one(s)); test_one(s); } + + { // Validate a view borrowed range + + constexpr auto v = views::iota(0ull, ranges::size(expected_keys)) | std::views::transform([](auto i) { + return std::make_pair(expected_keys[i], expected_values[i]); + }); + STATIC_ASSERT(test_one(v)); + test_one(v); + } } From 3e94a791d1731a30992f585a5817223fd25a1ee9 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 23 Apr 2021 14:45:18 +0200 Subject: [PATCH 2/4] Fix noexcept specification --- stl/inc/ranges | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 739e6e55905..6a52e7135d2 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -3771,13 +3771,16 @@ namespace ranges { } _NODISCARD constexpr decltype(auto) operator*() const - noexcept(noexcept(_STD get<_Index>(*_Current))) /* strengthened */ { - if constexpr (is_reference_v>) { - return _STD get<_Index>(*_Current); - } else { - using _ElemTy = remove_cv_t>>; - return static_cast<_ElemTy>(_STD get<_Index>(*_Current)); - } + noexcept(noexcept(_STD get<_Index>(*_Current))) /* strengthened */ + requires is_reference_v> { + return _STD get<_Index>(*_Current); + } + + _NODISCARD constexpr decltype(auto) operator*() const noexcept( + is_nothrow_move_constructible_v>>> // + && noexcept(_STD get<_Index>(*_Current))) /* strengthened */ { + using _ElemTy = remove_cv_t>>; + return static_cast<_ElemTy>(_STD get<_Index>(*_Current)); } constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ { @@ -3840,16 +3843,22 @@ namespace ranges { _NODISCARD constexpr decltype(auto) operator[](const difference_type _Idx) const noexcept(noexcept(_STD get<_Index>(*(_Current + _Idx)))) /* strengthened */ + requires random_access_range<_Base>&& is_reference_v> { +#if _ITERATOR_DEBUG_LEVEL != 0 + _Verify_offset(_Idx); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + return _STD get<_Index>(*(_Current + _Idx)); + } + + _NODISCARD constexpr decltype(auto) operator[](const difference_type _Idx) const noexcept( + is_nothrow_move_constructible_v>>> // + && noexcept(_STD get<_Index>(*(_Current + _Idx)))) /* strengthened */ requires random_access_range<_Base> { #if _ITERATOR_DEBUG_LEVEL != 0 _Verify_offset(_Idx); #endif // _ITERATOR_DEBUG_LEVEL != 0 - if constexpr (is_reference_v>) { - return _STD get<_Index>(*(_Current + _Idx)); - } else { - using _ElemTy = remove_cv_t>>; - return static_cast<_ElemTy>(_STD get<_Index>(*(_Current + _Idx))); - } + using _ElemTy = remove_cv_t>>; + return static_cast<_ElemTy>(_STD get<_Index>(*(_Current + _Idx))); } _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( From 81ca7930093c6d9a47907f4d306312c77664fb2c Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 29 Apr 2021 14:49:33 -0700 Subject: [PATCH 3/4] review comments; conditional noexcept --- stl/inc/ranges | 20 +++++++++---------- .../std/tests/P0896R4_views_elements/test.cpp | 6 ++---- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 6a52e7135d2..299174e6468 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -3735,7 +3735,8 @@ namespace ranges { template friend class _Sentinel; - using _Base = _Maybe_const<_Const, _Vw>; + using _Base = _Maybe_const<_Const, _Vw>; + using _ElemTy = tuple_element_t<_Index, range_value_t<_Base>>; iterator_t<_Base> _Current{}; @@ -3743,7 +3744,7 @@ namespace ranges { using iterator_concept = conditional_t, random_access_iterator_tag, conditional_t, bidirectional_iterator_tag, conditional_t, forward_iterator_tag, input_iterator_tag>>>; - using value_type = remove_cvref_t>>; + using value_type = remove_cvref_t<_ElemTy>; using difference_type = range_difference_t<_Base>; _Iterator() = default; @@ -3776,11 +3777,9 @@ namespace ranges { return _STD get<_Index>(*_Current); } - _NODISCARD constexpr decltype(auto) operator*() const noexcept( - is_nothrow_move_constructible_v>>> // + _NODISCARD constexpr decltype(auto) operator*() const noexcept(is_nothrow_move_constructible_v<_ElemTy> // && noexcept(_STD get<_Index>(*_Current))) /* strengthened */ { - using _ElemTy = remove_cv_t>>; - return static_cast<_ElemTy>(_STD get<_Index>(*_Current)); + return static_cast>(_STD get<_Index>(*_Current)); } constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ { @@ -3850,15 +3849,14 @@ namespace ranges { return _STD get<_Index>(*(_Current + _Idx)); } - _NODISCARD constexpr decltype(auto) operator[](const difference_type _Idx) const noexcept( - is_nothrow_move_constructible_v>>> // - && noexcept(_STD get<_Index>(*(_Current + _Idx)))) /* strengthened */ + _NODISCARD constexpr decltype(auto) operator[](const difference_type _Idx) const + noexcept(is_nothrow_move_constructible_v<_ElemTy> // + && noexcept(_STD get<_Index>(*(_Current + _Idx)))) /* strengthened */ requires random_access_range<_Base> { #if _ITERATOR_DEBUG_LEVEL != 0 _Verify_offset(_Idx); #endif // _ITERATOR_DEBUG_LEVEL != 0 - using _ElemTy = remove_cv_t>>; - return static_cast<_ElemTy>(_STD get<_Index>(*(_Current + _Idx))); + return static_cast>(_STD get<_Index>(*(_Current + _Idx))); } _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( diff --git a/tests/std/tests/P0896R4_views_elements/test.cpp b/tests/std/tests/P0896R4_views_elements/test.cpp index 8484144dc2d..910ded5e096 100644 --- a/tests/std/tests/P0896R4_views_elements/test.cpp +++ b/tests/std/tests/P0896R4_views_elements/test.cpp @@ -416,10 +416,8 @@ int main() { } { // Validate a view borrowed range - - constexpr auto v = views::iota(0ull, ranges::size(expected_keys)) | std::views::transform([](auto i) { - return std::make_pair(expected_keys[i], expected_values[i]); - }); + constexpr auto v = views::iota(0ull, ranges::size(expected_keys)) + | views::transform([](auto i) { return make_pair(expected_keys[i], expected_values[i]); }); STATIC_ASSERT(test_one(v)); test_one(v); } From 8a8921d6d320e07016af2af73194a36c343c6869 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 29 Apr 2021 16:18:13 -0700 Subject: [PATCH 4/4] Don't extract `_ElemTy` incorrectly --- stl/inc/ranges | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 299174e6468..f1e8e2317b3 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -3735,8 +3735,7 @@ namespace ranges { template friend class _Sentinel; - using _Base = _Maybe_const<_Const, _Vw>; - using _ElemTy = tuple_element_t<_Index, range_value_t<_Base>>; + using _Base = _Maybe_const<_Const, _Vw>; iterator_t<_Base> _Current{}; @@ -3744,7 +3743,7 @@ namespace ranges { using iterator_concept = conditional_t, random_access_iterator_tag, conditional_t, bidirectional_iterator_tag, conditional_t, forward_iterator_tag, input_iterator_tag>>>; - using value_type = remove_cvref_t<_ElemTy>; + using value_type = remove_cvref_t>>; using difference_type = range_difference_t<_Base>; _Iterator() = default; @@ -3777,9 +3776,11 @@ namespace ranges { return _STD get<_Index>(*_Current); } - _NODISCARD constexpr decltype(auto) operator*() const noexcept(is_nothrow_move_constructible_v<_ElemTy> // - && noexcept(_STD get<_Index>(*_Current))) /* strengthened */ { - return static_cast>(_STD get<_Index>(*_Current)); + _NODISCARD constexpr decltype(auto) operator*() const + noexcept(is_nothrow_move_constructible_v>> // + && noexcept(_STD get<_Index>(*_Current))) /* strengthened */ { + using _ElemTy = remove_cv_t>>; + return static_cast<_ElemTy>(_STD get<_Index>(*_Current)); } constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ { @@ -3850,13 +3851,14 @@ namespace ranges { } _NODISCARD constexpr decltype(auto) operator[](const difference_type _Idx) const - noexcept(is_nothrow_move_constructible_v<_ElemTy> // + noexcept(is_nothrow_move_constructible_v>> // && noexcept(_STD get<_Index>(*(_Current + _Idx)))) /* strengthened */ requires random_access_range<_Base> { #if _ITERATOR_DEBUG_LEVEL != 0 _Verify_offset(_Idx); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return static_cast>(_STD get<_Index>(*(_Current + _Idx))); + using _ElemTy = remove_cv_t>>; + return static_cast<_ElemTy>(_STD get<_Index>(*(_Current + _Idx))); } _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept(