https://gcc.gnu.org/g:4d8a55ac552627ebf9bf50d28a35459cba58d8c6
commit r14-10793-g4d8a55ac552627ebf9bf50d28a35459cba58d8c6 Author: Jonathan Wakely <jwak...@redhat.com> Date: Sun Oct 13 21:47:14 2024 +0100 libstdc++: Implement LWG 3564 for ranges::transform_view 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 <ppa...@redhat.com> (cherry picked from commit dde19c600c3c8a1d765c9b4961d2556e89edad14) Diff: --- libstdc++-v3/include/std/ranges | 9 +++++++-- .../testsuite/std/ranges/adaptors/transform.cc | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 59a251536208..2c8a8535d396 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -1870,8 +1870,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 @@ -1920,7 +1924,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; diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc index bcb18a3fc6c8..ca695349650a 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc @@ -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(); }