]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix elements_view::operator* and operator[] [LWG 3502]
authorPatrick Palka <ppalka@redhat.com>
Thu, 8 Apr 2021 20:45:22 +0000 (16:45 -0400)
committerPatrick Palka <ppalka@redhat.com>
Thu, 8 Apr 2021 20:45:22 +0000 (16:45 -0400)
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.

libstdc++-v3/include/std/ranges
libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc

index 978578197dc050efaf85a89d5657007cc43b5880..cfcbcaba06552642c44560136aa5c3526ee3e0ba 100644 (file)
@@ -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)
index b0d122f8db5f2dc59bd658baa813bf8c1f149c10..134afd6a8732b73f8e67778fc50e040cd6b11bb4 100644 (file)
@@ -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();
 }