]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Implement LWG 3564 for ranges::transform_view
authorJonathan Wakely <jwakely@redhat.com>
Sun, 13 Oct 2024 20:47:14 +0000 (21:47 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 14 Oct 2024 21:07:28 +0000 (22:07 +0100)
The _Iterator<true> type returned by begin() const uses const F& to
transform the elements, so it should use const F& to determine the
iterator's value_type and iterator_category as well.

This was accepted into the WP in July 2022.

libstdc++-v3/ChangeLog:

* include/std/ranges (transform_view:_Iterator): Use const F&
to determine value_type and iterator_category of
_Iterator<true>, as per LWG 3564.
* testsuite/std/ranges/adaptors/transform.cc: Check value_type
and iterator_category.

Reviewed-by: Patrick Palka <ppalka@redhat.com>
libstdc++-v3/include/std/ranges
libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc

index 6e6e3b97d82f5557996cd99b4c8a7261fbe7f420..98442dcfbd5177397544306ae7789284ac387636 100644 (file)
@@ -1886,8 +1886,12 @@ namespace views::__adaptor
          static auto
          _S_iter_cat()
          {
+           // _GLIBCXX_RESOLVE_LIB_DEFECTS
+           // 3564. transform_view::iterator<true>::value_type and
+           // iterator_category should use const F&
            using _Base = transform_view::_Base<_Const>;
-           using _Res = invoke_result_t<_Fp&, range_reference_t<_Base>>;
+           using _Res = invoke_result_t<__maybe_const_t<_Const, _Fp>&,
+                                        range_reference_t<_Base>>;
            if constexpr (is_lvalue_reference_v<_Res>)
              {
                using _Cat
@@ -1936,7 +1940,8 @@ namespace views::__adaptor
          using iterator_concept = decltype(_S_iter_concept());
          // iterator_category defined in __transform_view_iter_cat
          using value_type
-           = remove_cvref_t<invoke_result_t<_Fp&, range_reference_t<_Base>>>;
+           = remove_cvref_t<invoke_result_t<__maybe_const_t<_Const, _Fp>&,
+                                            range_reference_t<_Base>>>;
          using difference_type = range_difference_t<_Base>;
 
          _Iterator() requires default_initializable<_Base_iter> = default;
index bcb18a3fc6c85e83dc4861814270be3339f84f52..ca695349650a5e0d0aaeff47e2355785d104d5cc 100644 (file)
@@ -196,6 +196,24 @@ test09()
 #endif
 }
 
+void
+test10()
+{
+  struct F {
+    short operator()(int) { return 0; }
+    const int& operator()(const int& i) const { return i; }
+  };
+
+  int x[] {2, 4};
+  const auto xform = x | views::transform(F{});
+  using const_iterator = decltype(xform.begin());
+  // LWG 3564. transform_view::iterator<true>::value_type and iterator_category
+  // should use const F&
+  static_assert(std::same_as<std::iter_value_t<const_iterator>, int>);
+  using cat = std::iterator_traits<const_iterator>::iterator_category;
+  static_assert(std::same_as<cat, std::random_access_iterator_tag>);
+}
+
 int
 main()
 {
@@ -208,4 +226,5 @@ main()
   test07();
   test08();
   test09();
+  test10();
 }