Message ID | 20241013235310.1722385-1-jwakely@redhat.com |
---|---|
State | New |
Headers | show |
Series | libstdc++: Implement LWG 3564 for ranges::transform_view | expand |
On Mon, 14 Oct 2024, Jonathan Wakely wrote: > Tested x86_64-linux. > > -- >8 -- > > 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. > --- > libstdc++-v3/include/std/ranges | 9 +++++++-- > .../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 6e6e3b97d82..f0d81cbea0c 100644 > --- a/libstdc++-v3/include/std/ranges > +++ b/libstdc++-v3/include/std/ranges > @@ -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 _Fpc = __detail::__maybe_const_t<_Const, _Fp>; We can use __maybe_const_t unqualified here (ever since r13-3758-gf471cb71c86c1e). > using _Base = transform_view::_Base<_Const>; > - using _Res = invoke_result_t<_Fp&, range_reference_t<_Base>>; > + using _Res = invoke_result_t<_Fpc&, range_reference_t<_Base>>; > if constexpr (is_lvalue_reference_v<_Res>) > { > using _Cat > @@ -1927,6 +1931,7 @@ namespace views::__adaptor > return input_iterator_tag{}; > } > > + using _Fpc = __detail::__maybe_const_t<_Const, _Fp>; Same here. LGTM besides that. > using _Base_iter = iterator_t<_Base>; > > _Base_iter _M_current = _Base_iter(); > @@ -1936,7 +1941,7 @@ 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<_Fpc&, 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 bcb18a3fc6c..ca695349650 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(); > } > -- > 2.46.2 > >
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 6e6e3b97d82..f0d81cbea0c 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -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 _Fpc = __detail::__maybe_const_t<_Const, _Fp>; using _Base = transform_view::_Base<_Const>; - using _Res = invoke_result_t<_Fp&, range_reference_t<_Base>>; + using _Res = invoke_result_t<_Fpc&, range_reference_t<_Base>>; if constexpr (is_lvalue_reference_v<_Res>) { using _Cat @@ -1927,6 +1931,7 @@ namespace views::__adaptor return input_iterator_tag{}; } + using _Fpc = __detail::__maybe_const_t<_Const, _Fp>; using _Base_iter = iterator_t<_Base>; _Base_iter _M_current = _Base_iter(); @@ -1936,7 +1941,7 @@ 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<_Fpc&, 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 bcb18a3fc6c..ca695349650 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(); }