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
>
>