On Tue, Mar 10, 2026 at 6:37 PM Jonathan Wakely <[email protected]> wrote:

> Implement the resolution of LWG 444, accepted in Kona 2025.
>
The issue number is 4x4, not 3x4.

>
> The new value to be assigned to the matching elements should default to
> the value type of the range, not the type returned by the projection.
> The type returned by the projection is only used to find the matching
> elements, and might not be assignable to the value type at all.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/ranges_algo.h (__replace_fn, __replace_if_fn):
>         Change default template argument for type of new value, as per
>         LWG 4444.
>         * testsuite/25_algorithms/replace/lwg4444.cc: New test.
>         * testsuite/25_algorithms/replace_if/lwg4444.cc: New test.
> ---
>
> Tested x86_64-linux.
>
LGTM.

>
>  libstdc++-v3/include/bits/ranges_algo.h       |  8 ++---
>  .../25_algorithms/replace/lwg4444.cc          | 30 ++++++++++++++++++
>  .../25_algorithms/replace_if/lwg4444.cc       | 31 +++++++++++++++++++
>  3 files changed, 65 insertions(+), 4 deletions(-)
>  create mode 100644 libstdc++-v3/testsuite/25_algorithms/replace/lwg4444.cc
>  create mode 100644
> libstdc++-v3/testsuite/25_algorithms/replace_if/lwg4444.cc
>
> diff --git a/libstdc++-v3/include/bits/ranges_algo.h
> b/libstdc++-v3/include/bits/ranges_algo.h
> index 54f0ac8545c5..0d1928d52a2f 100644
> --- a/libstdc++-v3/include/bits/ranges_algo.h
> +++ b/libstdc++-v3/include/bits/ranges_algo.h
> @@ -1073,7 +1073,7 @@ namespace ranges
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
>              typename _Proj = identity,
>              typename _Tp1 _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
> -            typename _Tp2 _GLIBCXX26_DEF_VAL_T(_Tp1)>
> +            typename _Tp2 _GLIBCXX26_DEF_VAL_T(iter_value_t<_Iter>)>
>        requires indirectly_writable<_Iter, const _Tp2&>
>         && indirect_binary_predicate<ranges::equal_to, projected<_Iter,
> _Proj>,
>                                      const _Tp1*>
> @@ -1091,7 +1091,7 @@ namespace ranges
>      template<input_range _Range, typename _Proj = identity,
>              typename _Tp1
>                _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
> -            typename _Tp2 _GLIBCXX26_DEF_VAL_T(_Tp1)>
> +            typename _Tp2 _GLIBCXX26_DEF_VAL_T(range_value_t<_Range>)>
>        requires indirectly_writable<iterator_t<_Range>, const _Tp2&>
>         && indirect_binary_predicate<ranges::equal_to,
>                                      projected<iterator_t<_Range>, _Proj>,
> @@ -1112,7 +1112,7 @@ namespace ranges
>    {
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
>              typename _Proj = identity,
> -            typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
> +            typename _Tp _GLIBCXX26_DEF_VAL_T(iter_value_t<_Iter>),
>              indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
>        requires indirectly_writable<_Iter, const _Tp&>
>        constexpr _Iter
> @@ -1127,7 +1127,7 @@ namespace ranges
>
>      template<input_range _Range, typename _Proj = identity,
>              typename _Tp
> -              _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
> +              _GLIBCXX26_DEF_VAL_T(range_value_t<_Range>),
>              indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
>                _Pred>
>        requires indirectly_writable<iterator_t<_Range>, const _Tp&>
> diff --git a/libstdc++-v3/testsuite/25_algorithms/replace/lwg4444.cc
> b/libstdc++-v3/testsuite/25_algorithms/replace/lwg4444.cc
> new file mode 100644
> index 000000000000..a870815e83c9
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/25_algorithms/replace/lwg4444.cc
> @@ -0,0 +1,30 @@
> +// { dg-do run { target c++26 } }
> +
> +// LWG 4444. Fix default template arguments for ranges::replace [...]
> +
> +#include <algorithm>
> +#include <testsuite_hooks.h>
> +
> +struct S { int i; int j; };
> +
> +void
> +test_replace_iters()
> +{
> +  S s[2] = { {10, 11}, {20, 22} };
> +  std::ranges::replace(s, s+2, 20, {30, 33}, &S::i);
>
Nice and succint way to test that.

> +  VERIFY( s[1].j == 33 );
> +}
> +
> +void
> +test_replace_range()
> +{
> +  S s[2] = { {10, 11}, {20, 22} };
> +  std::ranges::replace(s, 20, {40, 44}, &S::i);
> +  VERIFY( s[1].j == 44 );
> +}
> +
> +int main()
> +{
> +  test_replace_iters();
> +  test_replace_range();
> +}
> diff --git a/libstdc++-v3/testsuite/25_algorithms/replace_if/lwg4444.cc
> b/libstdc++-v3/testsuite/25_algorithms/replace_if/lwg4444.cc
> new file mode 100644
> index 000000000000..bcc58fa7e959
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/25_algorithms/replace_if/lwg4444.cc
> @@ -0,0 +1,31 @@
> +// { dg-do run { target c++26 } }
> +
> +// LWG 4444. Fix default template arguments for [...] ranges::replace_if
> +
> +#include <algorithm>
> +#include <testsuite_hooks.h>
> +
> +struct S { int i; int j; };
> +auto twenty = [](int i) { return i == 20; };
> +
> +void
> +test_replace_if_iters()
> +{
> +  S s[2] = { {10, 11}, {20, 22} };
> +  std::ranges::replace_if(s, s+2, twenty, {30, 33}, &S::i);
> +  VERIFY( s[1].j == 33 );
> +}
> +
> +void
> +test_replace_if_range()
> +{
> +  S s[2] = { {10, 11}, {20, 22} };
> +  std::ranges::replace_if(s, twenty, {40, 44}, &S::i);
> +  VERIFY( s[1].j == 44 );
> +}
> +
> +int main()
> +{
> +  test_replace_if_iters();
> +  test_replace_if_range();
> +}
> --
> 2.53.0
>
>

Reply via email to