diff options
author | Patrick Palka <ppalka@redhat.com> | 2021-04-08 16:45:22 -0400 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2021-04-08 16:45:22 -0400 |
commit | c7fe68f3652ceefaf297611d1e64c8d9da43ad93 (patch) | |
tree | 7994ac53a4b58616cc7793a8f3f69c824670ce5c /libstdc++-v3 | |
parent | be8d5f99f50cf282c21632e60fe1d8857bb5a554 (diff) |
libstdc++: Fix elements_view::operator* and operator[] [LWG 3502]
While we're modifying elements_view, this also implements the one-line
resolution of LWG 3492.
libstdc++-v3/ChangeLog:
* include/std/ranges (__detail::__returnable_element): New
concept.
(elements_view): Use this concept in its constraints. Add
missing private access specifier.
(elements_view::_S_get_element): Define as per LWG 3502.
(elements_view::operator*, elements_view::operator[]): Use
_S_get_element.
(elements_view::operator++): Remove unnecessary constraint
as per LWG 3492.
* testsuite/std/ranges/adaptors/elements.cc (test05): New test.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/include/std/ranges | 26 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc | 16 |
2 files changed, 38 insertions, 4 deletions
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 978578197dc..cfcbcaba065 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -3234,6 +3234,10 @@ namespace views::__adaptor { std::get<_Nm>(__t) } -> convertible_to<const tuple_element_t<_Nm, _Tp>&>; }; + + template<typename _Tp, size_t _Nm> + concept __returnable_element + = is_reference_v<_Tp> || move_constructible<tuple_element_t<_Nm, _Tp>>; } template<input_range _Vp, size_t _Nm> @@ -3241,6 +3245,7 @@ namespace views::__adaptor && __detail::__has_tuple_element<range_value_t<_Vp>, _Nm> && __detail::__has_tuple_element<remove_reference_t<range_reference_t<_Vp>>, _Nm> + && __detail::__returnable_element<range_reference_t<_Vp>, _Nm> class elements_view : public view_interface<elements_view<_Vp, _Nm>> { public: @@ -3298,10 +3303,23 @@ namespace views::__adaptor template<bool _Const> struct _Iterator { + private: using _Base = __detail::__maybe_const_t<_Const, _Vp>; iterator_t<_Base> _M_current = iterator_t<_Base>(); + static constexpr decltype(auto) + _S_get_element(const iterator_t<_Base>& __i) + { + if constexpr (is_reference_v<range_reference_t<_Base>>) + return std::get<_Nm>(*__i); + else + { + using _Et = remove_cv_t<tuple_element_t<_Nm, range_reference_t<_Base>>>; + return static_cast<_Et>(std::get<_Nm>(*__i)); + } + } + friend _Iterator<!_Const>; public: @@ -3334,8 +3352,8 @@ namespace views::__adaptor { return std::move(_M_current); } constexpr decltype(auto) - operator*() const - { return std::get<_Nm>(*_M_current); } + operator*() const + { return _S_get_element(_M_current); } constexpr _Iterator& operator++() @@ -3345,7 +3363,7 @@ namespace views::__adaptor } constexpr void - operator++(int) requires (!forward_range<_Base>) + operator++(int) { ++_M_current; } constexpr _Iterator @@ -3390,7 +3408,7 @@ namespace views::__adaptor constexpr decltype(auto) operator[](difference_type __n) const requires random_access_range<_Base> - { return std::get<_Nm>(*(_M_current + __n)); } + { return _S_get_element(_M_current + __n); } friend constexpr bool operator==(const _Iterator& __x, const _Iterator& __y) diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc index b0d122f8db5..134afd6a873 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc @@ -100,6 +100,21 @@ test04() static_assert(!requires { 0 | elements; }); } +void +test05() +{ + // LWG 3502 + std::vector<int> vec = {42}; + auto r1 = vec + | views::transform([](auto c) { return std::make_tuple(c, c); }) + | views::keys; + VERIFY( ranges::equal(r1, (int[]){42}) ); + + std::tuple<int, int> a[] = {{1,2},{3,4}}; + auto r2 = a | views::keys; + VERIFY( r2[0] == 1 && r2[1] == 3 ); +} + int main() { @@ -107,4 +122,5 @@ main() test02(); test03(); test04(); + test05(); } |