LGTM. Here are some valid examples that are currently rejected by libstdc++ in gnu-mode (which would be resolved by this patch):
https://godbolt.org/z/c14T6dazc <https://godbolt.org/z/eTeEPrf8E> #include <memory> #include <ranges> int main() { int x[5] = {}; auto out = std::views::iota(__int128(0), __int128(5)) | std::views::transform([&](int i) -> auto& { return x[i]; }); std::ranges::uninitialized_copy(std::views::single(0), out); } Jonathan Wakely <jwak...@redhat.com> 於 2025年4月4日 週五 下午6:52寫道: > In r15-8980-gf4b6acfc36fb1f I introduced a new function object for > finding the smaller of two distances. In bugzilla Hewill Kang pointed > out that we still need to explicitly convert the result back to the > right difference type, because the result might be an integer-like class > type that doesn't convert to an integral type explicitly. > > Rather than doing that conversion in the __mindist function object, I > think it's simpler to remove it again and just do a comparison and > assignment. We always want the result to have a specific type, so we can > just check if the value of the other type is smaller, and then convert > that to the other type if so. > > libstdc++-v3/ChangeLog: > > PR libstdc++/101587 > * include/bits/ranges_uninitialized.h (__detail::__mindist): > Remove. > (ranges::uninitialized_copy, ranges::uninitialized_copy_n) > (ranges::uninitialized_move, ranges::uninitialized_move_n): Use > comparison and assignment instead of __mindist. > * > testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc: > Check with ranges that use integer-like class type for > difference type. > * > testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc: > Likewise. > > Reviewed-by: Tomasz Kaminski <tkami...@redhat.com> > Reviewed-by: Hewill Kang <hewi...@gmail.com> > > --- > > Here's a v2 patch with added tests. No change to the code in the > header, just to the tests. > > Tested x86_64-linux. > > diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h > b/libstdc++-v3/include/bits/ranges_uninitialized.h > index b5580073a6a..12a714b68aa 100644 > --- a/libstdc++-v3/include/bits/ranges_uninitialized.h > +++ b/libstdc++-v3/include/bits/ranges_uninitialized.h > @@ -263,26 +263,6 @@ namespace ranges > inline constexpr __uninitialized_value_construct_n_fn > uninitialized_value_construct_n; > > - namespace __detail > - { > - // This is only intended for finding smaller iterator differences > below, > - // not as a general purpose replacement for std::min. > - struct __mindist_fn > - { > - template<typename _Dp1, typename _Dp2> > - constexpr common_type_t<_Dp1, _Dp2> > - operator()(_Dp1 __d1, _Dp2 __d2) const noexcept > - { > - // Every C++20 iterator I satisfies weakly_incrementable<I> which > - // requires signed-integer-like<iter_difference_t<I>>. > - static_assert(std::__detail::__is_signed_integer_like<_Dp1>); > - static_assert(std::__detail::__is_signed_integer_like<_Dp2>); > - return std::min<common_type_t<_Dp1, _Dp2>>(__d1, __d2); > - } > - }; > - inline constexpr __mindist_fn __mindist{}; > - } > - > template<typename _Iter, typename _Out> > using uninitialized_copy_result = in_out_result<_Iter, _Out>; > > @@ -305,10 +285,10 @@ namespace ranges > && is_trivially_assignable_v<_OutType&, > iter_reference_t<_Iter>>) > { > - auto __d1 = __ilast - __ifirst; > - auto __d2 = __olast - __ofirst; > - return ranges::copy_n(std::move(__ifirst), > - __detail::__mindist(__d1, __d2), > __ofirst); > + auto __d = __ilast - __ifirst; > + if (auto __d2 = __olast - __ofirst; __d2 < __d) > + __d = static_cast<iter_difference_t<_Iter>>(__d2); > + return ranges::copy_n(std::move(__ifirst), __d, __ofirst); > } > else > { > @@ -356,9 +336,9 @@ namespace ranges > && is_trivially_assignable_v<_OutType&, > iter_reference_t<_Iter>>) > { > - auto __d = __olast - __ofirst; > - return ranges::copy_n(std::move(__ifirst), > - __detail::__mindist(__n, __d), __ofirst); > + if (auto __d = __olast - __ofirst; __d < __n) > + __n = static_cast<iter_difference_t<_Iter>>(__d); > + return ranges::copy_n(std::move(__ifirst), __n, __ofirst); > } > else > { > @@ -397,11 +377,12 @@ namespace ranges > && is_trivially_assignable_v<_OutType&, > > iter_rvalue_reference_t<_Iter>>) > { > - auto __d1 = __ilast - __ifirst; > - auto __d2 = __olast - __ofirst; > + auto __d = __ilast - __ifirst; > + if (auto __d2 = __olast - __ofirst; __d2 < __d) > + __d = static_cast<iter_difference_t<_Iter>>(__d2); > auto [__in, __out] > = > ranges::copy_n(std::make_move_iterator(std::move(__ifirst)), > - __detail::__mindist(__d1, __d2), __ofirst); > + __d, __ofirst); > return {std::move(__in).base(), __out}; > } > else > @@ -452,10 +433,11 @@ namespace ranges > && is_trivially_assignable_v<_OutType&, > > iter_rvalue_reference_t<_Iter>>) > { > - auto __d = __olast - __ofirst; > + if (auto __d = __olast - __ofirst; __d < __n) > + __n = static_cast<iter_difference_t<_Iter>>(__d); > auto [__in, __out] > = > ranges::copy_n(std::make_move_iterator(std::move(__ifirst)), > - __detail::__mindist(__n, __d), __ofirst); > + __n, __ofirst); > return {std::move(__in).base(), __out}; > } > else > diff --git > a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc > index af3b73364ec..5dff0da4d20 100644 > --- > a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc > +++ > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc > @@ -178,12 +178,40 @@ test03() > void > test_pr101587() > { > - short in[1]; > + short in[1]{}; > __gnu_test::test_contiguous_range r(in); // difference_type is > integer-like > long out[1]; > std::span<long> o(out); // difference_type is ptrdiff_t > ranges::uninitialized_copy(r, o); > ranges::uninitialized_copy_n(ranges::begin(r), 0, o.begin(), o.end()); > + > + // iterator that has an integer-like class type for difference_type > + struct Iter > + { > + using value_type = long; > + using difference_type = std::ranges::__detail::__max_diff_type; > + > + long& operator*() const { return *p; } > + > + Iter& operator++() { ++p; return *this; } > + Iter operator++(int) { return Iter{p++}; } > + > + difference_type operator-(Iter i) const { return p - i.p; } > + bool operator==(const Iter&) const = default; > + > + long* p = nullptr; > + }; > + static_assert(std::sized_sentinel_for<Iter, Iter>); > + > + std::ranges::subrange<Iter> rmax(Iter{out+0}, Iter{out+1}); > + // Check with integer-like class type for output range: > + std::ranges::uninitialized_copy(in, rmax); > + std::ranges::uninitialized_copy_n(in+0, 1, rmax.begin(), rmax.end()); > + > + int to[1]; > + // And for input range: > + std::ranges::uninitialized_copy(rmax, to); > + std::ranges::uninitialized_copy_n(rmax.begin(), 1, to+0, to+1); > } > > int > diff --git > a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc > index fe82d1f156e..3e8124492d4 100644 > --- > a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc > +++ > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc > @@ -188,12 +188,39 @@ test03() > void > test_pr101587() > { > - short in[1]; > + short in[1]{}; > __gnu_test::test_contiguous_range r(in); // difference_type is > integer-like > long out[1]; > std::span<long> o(out); // difference_type is ptrdiff_t > ranges::uninitialized_move(r, o); > ranges::uninitialized_move_n(ranges::begin(r), 0, o.begin(), o.end()); > + > + struct Iter > + { > + using value_type = long; > + using difference_type = std::ranges::__detail::__max_diff_type; > + > + long& operator*() const { return *p; } > + > + Iter& operator++() { ++p; return *this; } > + Iter operator++(int) { return Iter{p++}; } > + > + difference_type operator-(Iter i) const { return p - i.p; } > + bool operator==(const Iter&) const = default; > + > + long* p = nullptr; > + }; > + static_assert(std::sized_sentinel_for<Iter, Iter>); > + > + std::ranges::subrange<Iter> rmax(Iter{out+0}, Iter{out+1}); > + // Check with integer-like class type for output range: > + std::ranges::uninitialized_move(in, rmax); > + std::ranges::uninitialized_move_n(in+0, 1, rmax.begin(), rmax.end()); > + > + int to[1]; > + // And for input range: > + std::ranges::uninitialized_copy(rmax, to); > + std::ranges::uninitialized_copy_n(rmax.begin(), 1, to+0, to+1); > } > > int > >