-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++][ranges] LWG3564: transform_view::iterator<true>::value_type
and iterator_category
should use const F&
#91816
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-libcxx Author: Xiaoyang Liu (xiaoyang-sde) ChangesIntroductionThis patch implements LWG3564:
ReferenceFull diff: https://github.com/llvm/llvm-project/pull/91816.diff 4 Files Affected:
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index 04f6e23375acd..fef60d289f86f 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -159,7 +159,7 @@
"`3660 <https://wg21.link/LWG3660>`__","``iterator_traits<common_iterator>::pointer`` should conform to §[iterator.traits]","February 2022","|Complete|","14.0","|ranges|"
"`3661 <https://wg21.link/LWG3661>`__","``constinit atomic<shared_ptr<T>> a(nullptr);`` should work","February 2022","",""
"","","","","",""
-"`3564 <https://wg21.link/LWG3564>`__","``transform_view::iterator<true>::value_type`` and ``iterator_category`` should use ``const F&``","July 2022","","","|ranges|"
+"`3564 <https://wg21.link/LWG3564>`__","``transform_view::iterator<true>::value_type`` and ``iterator_category`` should use ``const F&``","July 2022","|Complete|","19.0","|ranges|"
"`3617 <https://wg21.link/LWG3617>`__","``function``/``packaged_task`` deduction guides and deducing ``this``","July 2022","",""
"`3656 <https://wg21.link/LWG3656>`__","Inconsistent bit operations returning a count","July 2022","|Complete|","15.0",""
"`3659 <https://wg21.link/LWG3659>`__","Consider ``ATOMIC_FLAG_INIT`` undeprecation","July 2022","|Complete|","15.0"
diff --git a/libcxx/include/__ranges/transform_view.h b/libcxx/include/__ranges/transform_view.h
index dc3aaa59ed8c3..af973076e04f8 100644
--- a/libcxx/include/__ranges/transform_view.h
+++ b/libcxx/include/__ranges/transform_view.h
@@ -153,15 +153,15 @@ struct __transform_view_iterator_concept<_View> {
using type = forward_iterator_tag;
};
-template <class, class>
+template <class, class, bool>
struct __transform_view_iterator_category_base {};
-template <forward_range _View, class _Fn>
-struct __transform_view_iterator_category_base<_View, _Fn> {
+template <forward_range _View, class _Fn, bool _Const>
+struct __transform_view_iterator_category_base<_View, _Fn, _Const> {
using _Cat = typename iterator_traits<iterator_t<_View>>::iterator_category;
using iterator_category =
- conditional_t< is_reference_v<invoke_result_t<_Fn&, range_reference_t<_View>>>,
+ conditional_t< is_reference_v<invoke_result_t<__maybe_const<_Const, _Fn>&, range_reference_t<_View>>>,
conditional_t< derived_from<_Cat, contiguous_iterator_tag>, random_access_iterator_tag, _Cat >,
input_iterator_tag >;
};
@@ -173,7 +173,7 @@ template <input_range _View, copy_constructible _Fn>
# endif
requires __transform_view_constraints<_View, _Fn>
template <bool _Const>
-class transform_view<_View, _Fn>::__iterator : public __transform_view_iterator_category_base<_View, _Fn> {
+class transform_view<_View, _Fn>::__iterator : public __transform_view_iterator_category_base<_View, _Fn, _Const> {
using _Parent = __maybe_const<_Const, transform_view>;
using _Base = __maybe_const<_Const, _View>;
@@ -190,7 +190,7 @@ class transform_view<_View, _Fn>::__iterator : public __transform_view_iterator_
iterator_t<_Base> __current_ = iterator_t<_Base>();
using iterator_concept = typename __transform_view_iterator_concept<_View>::type;
- using value_type = remove_cvref_t<invoke_result_t<_Fn&, range_reference_t<_Base>>>;
+ using value_type = remove_cvref_t<invoke_result_t<__maybe_const<_Const, _Fn>&, range_reference_t<_Base>>>;
using difference_type = range_difference_t<_Base>;
_LIBCPP_HIDE_FROM_ABI __iterator()
diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/types.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/types.pass.cpp
index 25d8936f4e4eb..17340467f856b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/types.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/types.pass.cpp
@@ -61,6 +61,21 @@ constexpr bool test() {
static_assert(std::same_as<typename TIter::value_type, int>);
static_assert(std::same_as<typename TIter::difference_type, std::ptrdiff_t>);
}
+ {
+ // Member typedefs for random access iterator, LWG3564 mutable overload
+ using TView = std::ranges::transform_view<RandomAccessView, PlusOneMutableOverload>;
+ using TIter = std::ranges::iterator_t<TView>;
+ static_assert(std::same_as<typename TIter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<typename TIter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<typename TIter::value_type, int>);
+ static_assert(std::same_as<typename TIter::difference_type, std::ptrdiff_t>);
+
+ using CTIter = std::ranges::iterator_t<const TView>;
+ static_assert(std::same_as<typename CTIter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<typename CTIter::iterator_category, std::input_iterator_tag>); // Note: this is now input_iterator_tag.
+ static_assert(std::same_as<typename CTIter::value_type, int>);
+ static_assert(std::same_as<typename CTIter::difference_type, std::ptrdiff_t>);
+ }
{
// Member typedefs for bidirectional iterator.
using TView = std::ranges::transform_view<BidirectionalView, Increment>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/types.h b/libcxx/test/std/ranges/range.adaptors/range.transform/types.h
index 14f85722a8c19..9268a977b8109 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.transform/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.transform/types.h
@@ -137,6 +137,11 @@ struct PlusOne {
constexpr int operator()(int x) const { return x + 1; }
};
+struct PlusOneMutableOverload {
+ constexpr int operator()(int x) const { return x + 1; }
+ constexpr int& operator()(int& x) { return ++x; }
+};
+
struct Increment {
constexpr int& operator()(int& x) { return ++x; }
};
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the patch and sorry for the review delay. Let's move this to LLVM 20, rebase to get the CI running and merge once the CI is green. LGTM.
Feel free to merge this patch if it looks good! |
There is a new merge conflict. Can you rebase this patch? |
…' and 'iterator_category' should use 'const F&'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be merged once CI is green.
Thanks for resolving the merge conflict! Could you please restart the failed tests? It seems that these are false negatives. |
Done and merged. Thanks for your patch! |
Introduction
This patch implements LWG3564:
transform_view::iterator<true>::value_type
anditerator_category
should useconst F&
.transform_view
's iterator currently obtained from aconst transform_view
invoke the transformation function asconst
, but thevalue_type
anditerator_category
determination uses non-const
F&
.Reference