On Fri, 13 Sep 2024, Jonathan Wakely wrote:

> On Sat, 3 Aug 2024 at 00:10, Jonathan Wakely <jwak...@redhat.com> wrote:
> >
> > On Fri, 2 Aug 2024 at 23:49, Giuseppe D'Angelo
> > <giuseppe.dang...@kdab.com> wrote:
> > >
> > > Hello,
> > >
> > > as usual thank you for the review. V2 is attached.
> > >
> > > On 02/08/2024 14:38, Jonathan Wakely wrote:
> > > > On Fri, 2 Aug 2024 at 13:17, Jonathan Wakely <jwak...@redhat.com> wrote:
> > > >>
> > > >> On Fri, 2 Aug 2024 at 11:45, Giuseppe D'Angelo wrote:
> > > >>>
> > > >>> Hello,
> > > >>>
> > > >>> The attached patch adds support for P2248R8 + P3217R0 (Enabling
> > > >>> list-initialization for algorithms, C++26). The big question is 
> > > >>> whether
> > > >>> this keeps the code readable enough without introducing too much
> > > >>> #ifdef-ery, so any feedback is appreciated.
> > > >>
> > > >> Putting the extra args on the algorithmfwd.h declarations is a nice
> > > >> way to avoid any clutter on the definitions. I think that is very
> > > >> readable.
> > > >> Another option would be to not touch those forward declarations, but
> > > >> add new ones with the defaults:
> > > >>
> > > >> #if __glibcxx_default_template_type_for_algorithm_values
> > > >> // new declarations with default template args ...
> > > >> #endif
> > > >>
> > > >> But I think what you've done is good.
> > >
> > > I'll keep it then :)
> > >
> > > >> For ranges_algo.h I'm almost tempted to say we should just treat this
> > > >> as a DR, to avoid the #ifdef-ery. Almost.
> > > >> Is there any reason we can't rearrange the template parameters fo
> > > >> C++20 and C++23 mode? I don't think users are allowed to use explicit
> > > >> template argument lists for invoke e.g. ranges::find.operator()<Iter,
> > > >> Proj> so it should be unobservable if we change the order for C++20
> > > >> (and just don't add the default args until C++26). That might reduce
> > > >> the differences to just a line or two for each CPO.
> > >
> > > Indeed, users cannot rely on any specific order of the template
> > > arguments when calling algorithms. This is
> > >
> > > https://eel.is/c++draft/algorithms.requirements#15
> > >
> > > which has this note:
> > >
> > > "Consequently, an implementation can declare an algorithm with different
> > > template parameters than those presented"
> > >
> > > which of course does apply here: it's why P2248 could do these changes
> > > to begin with. The only reason why I kept them in the original order was
> > > a matter of caution, but sure, in the new patch I've changed them
> > > unconditionally and just used a macro to hide the default in pre-C++26
> > > modes. This should keep the code clean(er).
> > >
> > >
> > > > The merged wording also removes the redundant 'typename' from the
> > > > default arguments, but I think we might still need that for Clang
> > > > compat. I'm not sure when Clang fully implemented "down with
> > > > typename", but it was still causing issues some time last year.
> > >
> > > I hope it's fine if I keep it.
> >
> > Yes, certainly.
> >
> > This looks good to me now, thanks.
> >
> > Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
> >
> > Patrick, could you please review + test this some time next week? If
> > it's all fine and you're happy with it too, please push to trunk.

Sorry for completely missing this!

> 
> Looks like this wasn't applied. I've rebased it, but the new
> 23_containers/default_template_value.cc test fails.
> 
> The problem is that all the std::erase overloads for containers have this 
> added:
> 
>   template<typename _CharT, typename _Traits, typename _Alloc, typename _Up
>        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_CharT)>
> 
> But the definition of that macro expects an iterator, not the value type.
> 
> Was the new test actually run?
> 
> I've attached the rebased patch, which needs fixes for the std::erase 
> overloads.
> 

> commit 3098548ec2349339044d95a7e17d144913b493de
> Author: Jonathan Wakely <jwak...@redhat.com>
> Date:   Fri Sep 13 10:18:46 2024
> 
>     libstdc++: add default template parameters to algorithms
>     
>     This implements P2248R8 + P3217R0, both approved for C++26.
>     The changes are mostly mechanical; the struggle is to keep readability
>     with the pre-P2248 signatures.
>     
>     * For containers, "classic STL" algorithms and their parallel versions,
>       introduce a macro and amend their declarations/definitions with it.
>       The macro either expands to the defaulted parameter or to nothing
>       in pre-C++26 modes.
>     
>     * For range algorithms, we need to reorder their template parameters.
>       I've done so unconditionally, because users cannot rely on template
>       parameters of algorithms (this is explicitly authorized by
>       [algorithms.requirements]/15). The defaults are then hidden behind
>       another macro.
>     
>     libstdc++-v3/ChangeLog:
>     
>             * include/bits/iterator_concepts.h: Add projected_value_t.
>             * include/bits/algorithmfwd.h: Add the default template
>             parameter to the relevant forward declarations.
>             * include/pstl/glue_algorithm_defs.h: Likewise.
>             * include/bits/ranges_algo.h: Add the default template
>             parameter to range-based algorithms.
>             * include/bits/ranges_algobase.h: Likewise.
>             * include/bits/ranges_util.h: Likewise.
>             * include/bits/ranges_base.h: Add helper macros.
>             * include/bits/stl_iterator_base_types.h: Add helper macro.
>             * include/bits/version.def: Add the new feature-testing macro.
>             * include/bits/version.h: Regenerate.
>             * include/std/algorithm: Pull the feature-testing macro.
>             * include/std/ranges: Likewise.
>             * include/std/deque: Pull the feature-testing macro, add
>             the default for std::erase.
>             * include/std/forward_list: Likewise.
>             * include/std/list: Likewise.
>             * include/std/string: Likewise.
>             * include/std/vector: Likewise.
>             * testsuite/23_containers/default_template_value.cc: New test.
>             * testsuite/25_algorithms/default_template_value.cc: New test.
>     
>     Signed-off-by: Giuseppe D'Angelo <giuseppe.dang...@kdab.com>
> 
> diff --git a/libstdc++-v3/include/bits/algorithmfwd.h 
> b/libstdc++-v3/include/bits/algorithmfwd.h
> index 34bf9921f43..88fac34e72f 100644
> --- a/libstdc++-v3/include/bits/algorithmfwd.h
> +++ b/libstdc++-v3/include/bits/algorithmfwd.h
> @@ -203,12 +203,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      any_of(_IIter, _IIter, _Predicate);
>  #endif
>  
> -  template<typename _FIter, typename _Tp>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      bool
>      binary_search(_FIter, _FIter, const _Tp&);
>  
> -  template<typename _FIter, typename _Tp, typename _Compare>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter),
> +        typename _Compare>
>      _GLIBCXX20_CONSTEXPR
>      bool
>      binary_search(_FIter, _FIter, const _Tp&, _Compare);
> @@ -250,22 +253,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>    // count
>    // count_if
>  
> -  template<typename _FIter, typename _Tp>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      pair<_FIter, _FIter>
>      equal_range(_FIter, _FIter, const _Tp&);
>  
> -  template<typename _FIter, typename _Tp, typename _Compare>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter),
> +        typename _Compare>
>      _GLIBCXX20_CONSTEXPR
>      pair<_FIter, _FIter>
>      equal_range(_FIter, _FIter, const _Tp&, _Compare);
>  
> -  template<typename _FIter, typename _Tp>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      void
>      fill(_FIter, _FIter, const _Tp&);
>  
> -  template<typename _OIter, typename _Size, typename _Tp>
> +  template<typename _OIter, typename _Size, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_OIter)>
>      _GLIBCXX20_CONSTEXPR
>      _OIter
>      fill_n(_OIter, _Size, const _Tp&);
> @@ -377,12 +385,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      void
>      iter_swap(_FIter1, _FIter2);
>  
> -  template<typename _FIter, typename _Tp>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      _FIter
>      lower_bound(_FIter, _FIter, const _Tp&);
>  
> -  template<typename _FIter, typename _Tp, typename _Compare>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter),
> +        typename _Compare>
>      _GLIBCXX20_CONSTEXPR
>      _FIter
>      lower_bound(_FIter, _FIter, const _Tp&, _Compare);
> @@ -553,7 +564,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  
>    // random_shuffle
>  
> -  template<typename _FIter, typename _Tp>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      _FIter
>      remove(_FIter, _FIter, const _Tp&);
> @@ -563,7 +575,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      _FIter
>      remove_if(_FIter, _FIter, _Predicate);
>  
> -  template<typename _IIter, typename _OIter, typename _Tp>
> +  template<typename _IIter, typename _OIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_IIter)>
>      _GLIBCXX20_CONSTEXPR
>      _OIter
>      remove_copy(_IIter, _IIter, _OIter, const _Tp&);
> @@ -580,7 +593,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      _OIter
>      replace_copy(_IIter, _IIter, _OIter, const _Tp&, const _Tp&);
>  
> -  template<typename _Iter, typename _OIter, typename _Predicate, typename 
> _Tp>
> +  template<typename _Iter, typename _OIter, typename _Predicate, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_OIter)>
>      _GLIBCXX20_CONSTEXPR
>      _OIter
>      replace_copy_if(_Iter, _Iter, _OIter, _Predicate, const _Tp&);
> @@ -673,12 +687,15 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
>  
>    // unique_copy
>  
> -  template<typename _FIter, typename _Tp>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      _FIter
>      upper_bound(_FIter, _FIter, const _Tp&);
>  
> -  template<typename _FIter, typename _Tp, typename _Compare>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter),
> +        typename _Compare>
>      _GLIBCXX20_CONSTEXPR
>      _FIter
>      upper_bound(_FIter, _FIter, const _Tp&, _Compare);
> @@ -695,7 +712,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
>      _FIter
>      adjacent_find(_FIter, _FIter, _BinaryPredicate);
>  
> -  template<typename _IIter, typename _Tp>
> +  template<typename _IIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_IIter)>
>      _GLIBCXX20_CONSTEXPR
>      typename iterator_traits<_IIter>::difference_type
>      count(_IIter, _IIter, const _Tp&);
> @@ -715,7 +733,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
>      bool
>      equal(_IIter1, _IIter1, _IIter2, _BinaryPredicate);
>  
> -  template<typename _IIter, typename _Tp>
> +  template<typename _IIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_IIter)>
>      _GLIBCXX20_CONSTEXPR
>      _IIter
>      find(_IIter, _IIter, const _Tp&);
> @@ -843,12 +862,14 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
>  #endif
>  #endif // HOSTED
>  
> -  template<typename _FIter, typename _Tp>
> +  template<typename _FIter, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      void
>      replace(_FIter, _FIter, const _Tp&, const _Tp&);
>  
> -  template<typename _FIter, typename _Predicate, typename _Tp>
> +  template<typename _FIter, typename _Predicate, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      void
>      replace_if(_FIter, _FIter, _Predicate, const _Tp&);
> @@ -863,12 +884,14 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
>      _FIter1
>      search(_FIter1, _FIter1, _FIter2, _FIter2, _BinaryPredicate);
>  
> -  template<typename _FIter, typename _Size, typename _Tp>
> +  template<typename _FIter, typename _Size, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter)>
>      _GLIBCXX20_CONSTEXPR
>      _FIter
>      search_n(_FIter, _FIter, _Size, const _Tp&);
>  
> -  template<typename _FIter, typename _Size, typename _Tp,
> +  template<typename _FIter, typename _Size, typename _Tp
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_FIter),
>          typename _BinaryPredicate>
>      _GLIBCXX20_CONSTEXPR
>      _FIter
> diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
> b/libstdc++-v3/include/bits/iterator_concepts.h
> index 642c709fee0..91ee6a4c6de 100644
> --- a/libstdc++-v3/include/bits/iterator_concepts.h
> +++ b/libstdc++-v3/include/bits/iterator_concepts.h
> @@ -826,6 +826,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        using type = invoke_result_t<_Proj&, __indirect_value_t<_Iter>>;
>      };
>  
> +#if __glibcxx_algorithm_default_value_type // C++ >= 26
> +  template<indirectly_readable _Iter,
> +        indirectly_regular_unary_invocable<_Iter> _Proj>
> +    using projected_value_t
> +     = remove_cvref_t<invoke_result_t<_Proj&, iter_value_t<_Iter>&>>;
> +#endif
> +
>    // [alg.req], common algorithm requirements
>  
>    /// [alg.req.ind.move], concept `indirectly_movable`
> diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
> b/libstdc++-v3/include/bits/ranges_algo.h
> index d258be0b93f..9a117ae1ff1 100644
> --- a/libstdc++-v3/include/bits/ranges_algo.h
> +++ b/libstdc++-v3/include/bits/ranges_algo.h
> @@ -281,7 +281,9 @@ namespace ranges
>    struct __count_fn
>    {
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp, typename _Proj = identity>
> +          typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to,
>                                        projected<_Iter, _Proj>,
>                                        const _Tp*>
> @@ -296,7 +298,9 @@ namespace ranges
>       return __n;
>        }
>  
> -    template<input_range _Range, typename _Tp, typename _Proj = identity>
> +    template<input_range _Range, typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to,
>                                        projected<iterator_t<_Range>, _Proj>,
>                                        const _Tp*>
> @@ -344,8 +348,10 @@ namespace ranges
>  
>    struct __search_n_fn
>    {
> -    template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
> -          typename _Pred = ranges::equal_to, typename _Proj = identity>
> +    template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
> +          typename _Pred = ranges::equal_to, typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj)>
>        requires indirectly_comparable<_Iter, const _Tp*, _Pred, _Proj>
>        constexpr subrange<_Iter>
>        operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> 
> __count,
> @@ -416,8 +422,10 @@ namespace ranges
>         }
>        }
>  
> -    template<forward_range _Range, typename _Tp,
> -          typename _Pred = ranges::equal_to, typename _Proj = identity>
> +    template<forward_range _Range,
> +          typename _Pred = ranges::equal_to, typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj)>
>        requires indirectly_comparable<iterator_t<_Range>, const _Tp*,
>                                    _Pred, _Proj>
>        constexpr borrowed_subrange_t<_Range>
> @@ -774,7 +782,11 @@ namespace ranges
>    struct __replace_fn
>    {
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp1, typename _Tp2, typename _Proj = identity>
> +          typename _Proj = identity,
> +          typename _Tp1
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj),
> +          typename _Tp2
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(_Tp1)>
>        requires indirectly_writable<_Iter, const _Tp2&>
>       && indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>,
>                                    const _Tp1*>
> @@ -789,8 +801,11 @@ namespace ranges
>       return __first;
>        }
>  
> -    template<input_range _Range,
> -          typename _Tp1, typename _Tp2, typename _Proj = identity>
> +    template<input_range _Range, typename _Proj = identity,
> +          typename _Tp1
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj),
> +          typename _Tp2
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(_Tp1)>
>        requires indirectly_writable<iterator_t<_Range>, const _Tp2&>
>       && indirect_binary_predicate<ranges::equal_to,
>                                    projected<iterator_t<_Range>, _Proj>,
> @@ -810,7 +825,9 @@ namespace ranges
>    struct __replace_if_fn
>    {
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp, typename _Proj = identity,
> +          typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj),
>            indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
>        requires indirectly_writable<_Iter, const _Tp&>
>        constexpr _Iter
> @@ -823,7 +840,9 @@ namespace ranges
>       return std::move(__first);
>        }
>  
> -    template<input_range _Range, typename _Tp, typename _Proj = identity,
> +    template<input_range _Range, typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj),
>            indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
>              _Pred>
>        requires indirectly_writable<iterator_t<_Range>, const _Tp&>
> @@ -844,11 +863,15 @@ namespace ranges
>    struct __replace_copy_fn
>    {
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp1, typename _Tp2, output_iterator<const _Tp2&> _Out,
> -          typename _Proj = identity>
> +          typename _Out, typename _Proj = identity,
> +          typename _Tp1
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj),
> +          typename _Tp2
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Out>)>
>        requires indirectly_copyable<_Iter, _Out>
>       && indirect_binary_predicate<ranges::equal_to,
>                                    projected<_Iter, _Proj>, const _Tp1*>
> +     && output_iterator<_Out, const _Tp2&>
>        constexpr replace_copy_result<_Iter, _Out>
>        operator()(_Iter __first, _Sent __last, _Out __result,
>                const _Tp1& __old_value, const _Tp2& __new_value,
> @@ -862,12 +885,17 @@ namespace ranges
>       return {std::move(__first), std::move(__result)};
>        }
>  
> -    template<input_range _Range, typename _Tp1, typename _Tp2,
> -          output_iterator<const _Tp2&> _Out, typename _Proj = identity>
> +    template<input_range _Range, typename _Out,
> +          typename _Proj = identity,
> +          typename _Tp1
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj),
> +          typename _Tp2
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Out>)>
>        requires indirectly_copyable<iterator_t<_Range>, _Out>
>       && indirect_binary_predicate<ranges::equal_to,
>                                    projected<iterator_t<_Range>, _Proj>,
>                                    const _Tp1*>
> +     && output_iterator<_Out, const _Tp2&>
>        constexpr replace_copy_result<borrowed_iterator_t<_Range>, _Out>
>        operator()(_Range&& __r, _Out __result,
>                const _Tp1& __old_value, const _Tp2& __new_value,
> @@ -887,10 +915,13 @@ namespace ranges
>    struct __replace_copy_if_fn
>    {
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp, output_iterator<const _Tp&> _Out,
> +          typename _Out,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Out>),
>            typename _Proj = identity,
>            indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
>        requires indirectly_copyable<_Iter, _Out>
> +     && output_iterator<_Out, const _Tp&>
>        constexpr replace_copy_if_result<_Iter, _Out>
>        operator()(_Iter __first, _Sent __last, _Out __result,
>                _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) const
> @@ -904,11 +935,14 @@ namespace ranges
>        }
>  
>      template<input_range _Range,
> -          typename _Tp, output_iterator<const _Tp&> _Out,
> +          typename _Out,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Out>),
>            typename _Proj = identity,
>            indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
>              _Pred>
>        requires indirectly_copyable<iterator_t<_Range>, _Out>
> +     && output_iterator<_Out, const _Tp&>
>        constexpr replace_copy_if_result<borrowed_iterator_t<_Range>, _Out>
>        operator()(_Range&& __r, _Out __result,
>                _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) const
> @@ -1004,7 +1038,9 @@ namespace ranges
>    struct __remove_fn
>    {
>      template<permutable _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp, typename _Proj = identity>
> +          typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to,
>                                        projected<_Iter, _Proj>,
>                                        const _Tp*>
> @@ -1019,7 +1055,9 @@ namespace ranges
>                                std::move(__pred), std::move(__proj));
>        }
>  
> -    template<forward_range _Range, typename _Tp, typename _Proj = identity>
> +    template<forward_range _Range, typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj)>
>        requires permutable<iterator_t<_Range>>
>       && indirect_binary_predicate<ranges::equal_to,
>                                    projected<iterator_t<_Range>, _Proj>,
> @@ -1079,7 +1117,9 @@ namespace ranges
>    struct __remove_copy_fn
>    {
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          weakly_incrementable _Out, typename _Tp, typename _Proj = identity>
> +          weakly_incrementable _Out, typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj)>
>        requires indirectly_copyable<_Iter, _Out>
>       && indirect_binary_predicate<ranges::equal_to,
>                                    projected<_Iter, _Proj>,
> @@ -1098,7 +1138,9 @@ namespace ranges
>        }
>  
>      template<input_range _Range, weakly_incrementable _Out,
> -          typename _Tp, typename _Proj = identity>
> +          typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj)>
>        requires indirectly_copyable<iterator_t<_Range>, _Out>
>       && indirect_binary_predicate<ranges::equal_to,
>                                    projected<iterator_t<_Range>, _Proj>,
> @@ -2047,7 +2089,9 @@ namespace ranges
>    struct __lower_bound_fn
>    {
>      template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp, typename _Proj = identity,
> +          typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj),
>            indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
>              _Comp = ranges::less>
>        constexpr _Iter
> @@ -2073,7 +2117,10 @@ namespace ranges
>       return __first;
>        }
>  
> -    template<forward_range _Range, typename _Tp, typename _Proj = identity,
> +    template<forward_range _Range,
> +          typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj),
>            indirect_strict_weak_order<const _Tp*,
>                                       projected<iterator_t<_Range>, _Proj>>
>              _Comp = ranges::less>
> @@ -2091,7 +2138,9 @@ namespace ranges
>    struct __upper_bound_fn
>    {
>      template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp, typename _Proj = identity,
> +          typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj),
>            indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
>              _Comp = ranges::less>
>        constexpr _Iter
> @@ -2117,7 +2166,10 @@ namespace ranges
>       return __first;
>        }
>  
> -    template<forward_range _Range, typename _Tp, typename _Proj = identity,
> +    template<forward_range _Range,
> +          typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj),
>            indirect_strict_weak_order<const _Tp*,
>                                       projected<iterator_t<_Range>, _Proj>>
>              _Comp = ranges::less>
> @@ -2135,7 +2187,9 @@ namespace ranges
>    struct __equal_range_fn
>    {
>      template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp, typename _Proj = identity,
> +          typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj),
>            indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
>              _Comp = ranges::less>
>        constexpr subrange<_Iter>
> @@ -2177,7 +2231,9 @@ namespace ranges
>        }
>  
>      template<forward_range _Range,
> -          typename _Tp, typename _Proj = identity,
> +          typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj),
>            indirect_strict_weak_order<const _Tp*,
>                                       projected<iterator_t<_Range>, _Proj>>
>              _Comp = ranges::less>
> @@ -2195,7 +2251,9 @@ namespace ranges
>    struct __binary_search_fn
>    {
>      template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
> -          typename _Tp, typename _Proj = identity,
> +          typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj),
>            indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
>              _Comp = ranges::less>
>        constexpr bool
> @@ -2210,7 +2268,9 @@ namespace ranges
>        }
>  
>      template<forward_range _Range,
> -          typename _Tp, typename _Proj = identity,
> +          typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj),
>            indirect_strict_weak_order<const _Tp*,
>                                       projected<iterator_t<_Range>, _Proj>>
>              _Comp = ranges::less>
> @@ -3469,14 +3529,19 @@ namespace ranges
>    struct __contains_fn
>    {
>      template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
> -         typename _Tp, typename _Proj = identity>
> +         typename _Proj = identity,
> +         typename _Tp
> +           _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to,
>                                        projected<_Iter, _Proj>, const _Tp*>
>        constexpr bool
>        operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj 
> __proj = {}) const
>        { return ranges::find(std::move(__first), __last, __value, 
> std::move(__proj)) != __last; }
>  
> -    template<input_range _Range, typename _Tp, typename _Proj = identity>
> +    template<input_range _Range,
> +         typename _Proj = identity,
> +         typename _Tp
> +           
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to,
>                                        projected<iterator_t<_Range>, _Proj>, 
> const _Tp*>
>        constexpr bool
> @@ -3525,7 +3590,10 @@ namespace ranges
>  
>    struct __find_last_fn
>    {
> -    template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename 
> _Tp, typename _Proj = identity>
> +    template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
> +          typename _Proj = identity,
> +          typename _Tp
> +            _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, 
> _Proj>, const _Tp*>
>        constexpr subrange<_Iter>
>        operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj 
> __proj = {}) const
> @@ -3556,7 +3624,9 @@ namespace ranges
>         }
>        }
>  
> -    template<forward_range _Range, typename _Tp, typename _Proj = identity>
> +    template<forward_range _Range, typename _Proj = identity,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to, 
> projected<iterator_t<_Range>, _Proj>, const _Tp*>
>        constexpr borrowed_subrange_t<_Range>
>        operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const
> @@ -3730,7 +3800,8 @@ namespace ranges
>       return _Ret{std::move(__first), std::move(__accum)};
>        }
>  
> -    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
> +    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Iter>),
>            __detail::__indirectly_binary_left_foldable<_Tp, _Iter> _Fp>
>        constexpr auto
>        operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
> @@ -3740,7 +3811,8 @@ namespace ranges
>                                 std::move(__init), std::move(__f));
>        }
>  
> -    template<input_range _Range, typename _Tp,
> +    template<input_range _Range, typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(range_value_t<_Range>),
>            __detail::__indirectly_binary_left_foldable<_Tp, 
> iterator_t<_Range>> _Fp>
>        constexpr auto
>        operator()(_Range&& __r, _Tp __init, _Fp __f) const
> @@ -3755,7 +3827,8 @@ namespace ranges
>  
>    struct __fold_left_fn
>    {
> -    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
> +    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Iter>),
>            __detail::__indirectly_binary_left_foldable<_Tp, _Iter> _Fp>
>        constexpr auto
>        operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
> @@ -3764,7 +3837,8 @@ namespace ranges
>                                          std::move(__init), 
> std::move(__f)).value;
>        }
>  
> -    template<input_range _Range, typename _Tp,
> +    template<input_range _Range, typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(range_value_t<_Range>),
>            __detail::__indirectly_binary_left_foldable<_Tp, 
> iterator_t<_Range>> _Fp>
>        constexpr auto
>        operator()(_Range&& __r, _Tp __init, _Fp __f) const
> @@ -3842,7 +3916,8 @@ namespace ranges
>  
>    struct __fold_right_fn
>    {
> -    template<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, 
> typename _Tp,
> +    template<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, 
> typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Iter>),
>            __detail::__indirectly_binary_right_foldable<_Tp, _Iter> _Fp>
>        constexpr auto
>        operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
> @@ -3859,7 +3934,8 @@ namespace ranges
>       return __accum;
>        }
>  
> -    template<bidirectional_range _Range, typename _Tp,
> +    template<bidirectional_range _Range, typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(range_value_t<_Range>),
>            __detail::__indirectly_binary_right_foldable<_Tp, 
> iterator_t<_Range>> _Fp>
>        constexpr auto
>        operator()(_Range&& __r, _Tp __init, _Fp __f) const
> diff --git a/libstdc++-v3/include/bits/ranges_algobase.h 
> b/libstdc++-v3/include/bits/ranges_algobase.h
> index fd35b8ba14c..39cf06bdd3e 100644
> --- a/libstdc++-v3/include/bits/ranges_algobase.h
> +++ b/libstdc++-v3/include/bits/ranges_algobase.h
> @@ -536,7 +536,9 @@ namespace ranges
>  
>    struct __fill_n_fn
>    {
> -    template<typename _Tp, output_iterator<const _Tp&> _Out>
> +    template<typename _Out, typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Out>)>
> +      requires output_iterator<_Out, const _Tp&>
>        constexpr _Out
>        operator()(_Out __first, iter_difference_t<_Out> __n,
>                const _Tp& __value) const
> @@ -581,8 +583,11 @@ namespace ranges
>  
>    struct __fill_fn
>    {
> -    template<typename _Tp,
> -          output_iterator<const _Tp&> _Out, sentinel_for<_Out> _Sent>
> +    template<typename _Out,
> +          sentinel_for<_Out> _Sent,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(iter_value_t<_Out>)>
> +      requires output_iterator<_Out, const _Tp&>
>        constexpr _Out
>        operator()(_Out __first, _Sent __last, const _Tp& __value) const
>        {
> @@ -608,7 +613,10 @@ namespace ranges
>         }
>        }
>  
> -    template<typename _Tp, output_range<const _Tp&> _Range>
> +    template<typename _Range,
> +          typename _Tp
> +            
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(range_value_t<_Range>)>
> +      requires output_range<_Range, const _Tp&>
>        constexpr borrowed_iterator_t<_Range>
>        operator()(_Range&& __r, const _Tp& __value) const
>        {
> diff --git a/libstdc++-v3/include/bits/ranges_base.h 
> b/libstdc++-v3/include/bits/ranges_base.h
> index 63eb552b48b..1a26df4c4c3 100644
> --- a/libstdc++-v3/include/bits/ranges_base.h
> +++ b/libstdc++-v3/include/bits/ranges_base.h
> @@ -39,6 +39,15 @@
>  #include <bits/max_size_type.h>
>  #include <bits/version.h>
>  
> +#if __glibcxx_algorithm_default_value_type // C++ >= 26
> +# define _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(_X) = _X
> +# define _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_I, _P) \
> +     = projected_value_t<_I, _P>
> +#else
> +# define _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE(_X)
> +# define _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_I, _P)
> +#endif
> +
>  #ifdef __cpp_lib_concepts
>  namespace std _GLIBCXX_VISIBILITY(default)
>  {
> diff --git a/libstdc++-v3/include/bits/ranges_util.h 
> b/libstdc++-v3/include/bits/ranges_util.h
> index e6d96073e87..139c272046f 100644
> --- a/libstdc++-v3/include/bits/ranges_util.h
> +++ b/libstdc++-v3/include/bits/ranges_util.h
> @@ -487,8 +487,10 @@ namespace ranges
>  {
>    struct __find_fn
>    {
> -    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
> -          typename _Proj = identity>
> +    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
> +          typename _Proj = identity,
> +          typename _Tp
> +          _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(_Iter, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to,
>                                        projected<_Iter, _Proj>, const _Tp*>
>        constexpr _Iter
> @@ -521,7 +523,9 @@ namespace ranges
>       return __first;
>        }
>  
> -    template<input_range _Range, typename _Tp, typename _Proj = identity>
> +    template<input_range _Range, typename _Proj = identity,
> +          typename _Tp
> +          
> _GLIBCXX26_RANGE_ALGORITHM_DEFAULT_VALUE_TYPE_PROJ(iterator_t<_Range>, _Proj)>
>        requires indirect_binary_predicate<ranges::equal_to,
>                                        projected<iterator_t<_Range>, _Proj>,
>                                        const _Tp*>
> diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h 
> b/libstdc++-v3/include/bits/stl_iterator_base_types.h
> index 07beec3554d..2b87324eb77 100644
> --- a/libstdc++-v3/include/bits/stl_iterator_base_types.h
> +++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h
> @@ -269,4 +269,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  _GLIBCXX_END_NAMESPACE_VERSION
>  } // namespace
>  
> +#if __glibcxx_algorithm_default_value_type // C++ >= 26
> +# define _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_Iterator) \
> +     = typename iterator_traits<_Iterator>::value_type
> +#else
> +# define _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_It)

Small nit, but these should consistently use _Iterator or _It as the
parameter name in both branches.

Maybe we should abbreviate these macro names to _GLIBCXX26_ALGO_DEF_VAL_T etc
so that we can fit most uses on the same line as the template parameter
declaration (without exceeding line length limits)?  Either way this patch
+ your followup LGTM.

> +#endif
> +
>  #endif /* _STL_ITERATOR_BASE_TYPES_H */
> diff --git a/libstdc++-v3/include/bits/version.def 
> b/libstdc++-v3/include/bits/version.def
> index bd3af9cba99..0475c8d002a 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -1782,6 +1782,14 @@ ftms = {
>    };
>  };
>  
> +ftms = {
> +  name = algorithm_default_value_type;
> +  values = {
> +    v = 202403;
> +    cxxmin = 26;
> +  };
> +};
> +
>  ftms = {
>    name = fstream_native_handle;
>    values = {
> diff --git a/libstdc++-v3/include/bits/version.h 
> b/libstdc++-v3/include/bits/version.h
> index 364e3a05f0e..73050a1ea35 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -1968,6 +1968,16 @@
>  #endif /* !defined(__cpp_lib_unreachable) && 
> defined(__glibcxx_want_unreachable) */
>  #undef __glibcxx_want_unreachable
>  
> +#if !defined(__cpp_lib_algorithm_default_value_type)
> +# if (__cplusplus >  202302L)
> +#  define __glibcxx_algorithm_default_value_type 202403L
> +#  if defined(__glibcxx_want_all) || 
> defined(__glibcxx_want_algorithm_default_value_type)
> +#   define __cpp_lib_algorithm_default_value_type 202403L
> +#  endif
> +# endif
> +#endif /* !defined(__cpp_lib_algorithm_default_value_type) && 
> defined(__glibcxx_want_algorithm_default_value_type) */
> +#undef __glibcxx_want_algorithm_default_value_type
> +
>  #if !defined(__cpp_lib_fstream_native_handle)
>  # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
>  #  define __glibcxx_fstream_native_handle 202306L
> diff --git a/libstdc++-v3/include/pstl/glue_algorithm_defs.h 
> b/libstdc++-v3/include/pstl/glue_algorithm_defs.h
> index cef78e22e31..cf997b5f3bc 100644
> --- a/libstdc++-v3/include/pstl/glue_algorithm_defs.h
> +++ b/libstdc++-v3/include/pstl/glue_algorithm_defs.h
> @@ -10,6 +10,7 @@
>  #ifndef _PSTL_GLUE_ALGORITHM_DEFS_H
>  #define _PSTL_GLUE_ALGORITHM_DEFS_H
>  
> +#include <bits/stl_iterator_base_types.h>
>  #include <bits/stl_pair.h>
>  
>  #include "execution_defs.h"
> @@ -55,7 +56,7 @@ template <class _ExecutionPolicy, class _ForwardIterator, 
> class _Predicate>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator>
>  find_if_not(_ExecutionPolicy&& __exec, _ForwardIterator __first, 
> _ForwardIterator __last, _Predicate __pred);
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator, class _Tp 
> _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator>
>  find(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator 
> __last, const _Tp& __value);
>  
> @@ -95,7 +96,7 @@ adjacent_find(_ExecutionPolicy&& __exec, _ForwardIterator 
> __first, _ForwardItera
>  
>  // [alg.count]
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator, class _Tp 
> _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy,
>                                                   typename 
> iterator_traits<_ForwardIterator>::difference_type>
>  count(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator 
> __last, const _Tp& __value);
> @@ -117,12 +118,12 @@ 
> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardItera
>  search(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, 
> _ForwardIterator1 __last, _ForwardIterator2 __s_first,
>         _ForwardIterator2 __s_last);
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class 
> _Tp, class _BinaryPredicate>
> +template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class 
> _Tp _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator), class 
> _BinaryPredicate>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator>
>  search_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, 
> _ForwardIterator __last, _Size __count,
>           const _Tp& __value, _BinaryPredicate __pred);
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class 
> _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class 
> _Tp _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator>
>  search_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, 
> _ForwardIterator __last, _Size __count,
>           const _Tp& __value);
> @@ -164,17 +165,17 @@ transform(_ExecutionPolicy&& __exec, _ForwardIterator1 
> __first1, _ForwardIterato
>  
>  // [alg.replace]
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class 
> _UnaryPredicate, class _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator, class 
> _UnaryPredicate, class _Tp 
> _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void>
>  replace_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, 
> _ForwardIterator __last, _UnaryPredicate __pred,
>             const _Tp& __new_value);
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator, class _Tp 
> _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void>
>  replace(_ExecutionPolicy&& __exec, _ForwardIterator __first, 
> _ForwardIterator __last, const _Tp& __old_value,
>          const _Tp& __new_value);
>  
> -template <class _ExecutionPolicy, class _ForwardIterator1, class 
> _ForwardIterator2, class _UnaryPredicate, class _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator1, class 
> _ForwardIterator2, class _UnaryPredicate, class _Tp 
> _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator2)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator2>
>  replace_copy_if(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, 
> _ForwardIterator1 __last,
>                  _ForwardIterator2 __result, _UnaryPredicate __pred, const 
> _Tp& __new_value);
> @@ -186,11 +187,11 @@ replace_copy(_ExecutionPolicy&& __exec, 
> _ForwardIterator1 __first, _ForwardItera
>  
>  // [alg.fill]
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator, class _Tp 
> _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void>
>  fill(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator 
> __last, const _Tp& __value);
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class 
> _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class 
> _Tp _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator>
>  fill_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __count, 
> const _Tp& __value);
>  
> @@ -210,7 +211,7 @@ 
> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardItera
>  remove_copy_if(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, 
> _ForwardIterator1 __last,
>                 _ForwardIterator2 __result, _Predicate __pred);
>  
> -template <class _ExecutionPolicy, class _ForwardIterator1, class 
> _ForwardIterator2, class _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator1, class 
> _ForwardIterator2, class _Tp 
> _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator1)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator2>
>  remove_copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, 
> _ForwardIterator1 __last, _ForwardIterator2 __result,
>              const _Tp& __value);
> @@ -219,7 +220,7 @@ template <class _ExecutionPolicy, class _ForwardIterator, 
> class _UnaryPredicate>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator>
>  remove_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, 
> _ForwardIterator __last, _UnaryPredicate __pred);
>  
> -template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
> +template <class _ExecutionPolicy, class _ForwardIterator, class _Tp 
> _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_ForwardIterator)>
>  __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, 
> _ForwardIterator>
>  remove(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator 
> __last, const _Tp& __value);
>  
> diff --git a/libstdc++-v3/include/std/algorithm 
> b/libstdc++-v3/include/std/algorithm
> index 163e6b5dca7..b410e7c281b 100644
> --- a/libstdc++-v3/include/std/algorithm
> +++ b/libstdc++-v3/include/std/algorithm
> @@ -63,6 +63,7 @@
>  # include <bits/ranges_algo.h>
>  #endif
>  
> +#define __glibcxx_want_algorithm_default_value_type
>  #define __glibcxx_want_clamp
>  #define __glibcxx_want_constexpr_algorithms
>  #define __glibcxx_want_freestanding_algorithm
> diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque
> index 69f8c0dcdcc..48d2e308bdd 100644
> --- a/libstdc++-v3/include/std/deque
> +++ b/libstdc++-v3/include/std/deque
> @@ -68,6 +68,7 @@
>  #include <bits/range_access.h>
>  #include <bits/deque.tcc>
>  
> +#define __glibcxx_want_algorithm_default_value_type
>  #define __glibcxx_want_allocator_traits_is_always_equal
>  #define __glibcxx_want_erase_if
>  #define __glibcxx_want_nonmember_container_access
> @@ -116,7 +117,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        return 0;
>      }
>  
> -  template<typename _Tp, typename _Alloc, typename _Up>
> +  template<typename _Tp, typename _Alloc, typename _Up
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_Tp)>
>      inline typename deque<_Tp, _Alloc>::size_type
>      erase(deque<_Tp, _Alloc>& __cont, const _Up& __value)
>      {
> diff --git a/libstdc++-v3/include/std/forward_list 
> b/libstdc++-v3/include/std/forward_list
> index dfd7d48d121..d03c965e82a 100644
> --- a/libstdc++-v3/include/std/forward_list
> +++ b/libstdc++-v3/include/std/forward_list
> @@ -45,6 +45,7 @@
>  # include <debug/forward_list>
>  #endif
>  
> +#define __glibcxx_want_algorithm_default_value_type
>  #define __glibcxx_want_allocator_traits_is_always_equal
>  #define __glibcxx_want_erase_if
>  #define __glibcxx_want_incomplete_container_elements
> @@ -75,7 +76,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred)
>      { return __cont.remove_if(__pred); }
>  
> -  template<typename _Tp, typename _Alloc, typename _Up>
> +  template<typename _Tp, typename _Alloc, typename _Up
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_Tp)>
>      inline typename forward_list<_Tp, _Alloc>::size_type
>      erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
>      {
> diff --git a/libstdc++-v3/include/std/list b/libstdc++-v3/include/std/list
> index ff632fc1ab2..e26ca11c468 100644
> --- a/libstdc++-v3/include/std/list
> +++ b/libstdc++-v3/include/std/list
> @@ -69,6 +69,7 @@
>  # include <debug/list>
>  #endif
>  
> +#define __glibcxx_want_algorithm_default_value_type
>  #define __glibcxx_want_allocator_traits_is_always_equal
>  #define __glibcxx_want_erase_if
>  #define __glibcxx_want_incomplete_container_elements
> @@ -99,7 +100,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred)
>      { return __cont.remove_if(__pred); }
>  
> -  template<typename _Tp, typename _Alloc, typename _Up>
> +  template<typename _Tp, typename _Alloc, typename _Up
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_Tp)>
>      inline typename list<_Tp, _Alloc>::size_type
>      erase(list<_Tp, _Alloc>& __cont, const _Up& __value)
>      {
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index aa08a48440c..7169c3a92aa 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -51,6 +51,7 @@
>  #include <bits/ranges_util.h>
>  #include <bits/refwrap.h>
>  
> +#define __glibcxx_want_algorithm_default_value_type
>  #define __glibcxx_want_ranges
>  #define __glibcxx_want_ranges_as_const
>  #define __glibcxx_want_ranges_as_rvalue
> diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string
> index 8db0802a282..461bf6450ae 100644
> --- a/libstdc++-v3/include/std/string
> +++ b/libstdc++-v3/include/std/string
> @@ -54,6 +54,7 @@
>  #include <bits/basic_string.h>
>  #include <bits/basic_string.tcc>
>  
> +#define __glibcxx_want_algorithm_default_value_type
>  #define __glibcxx_want_allocator_traits_is_always_equal
>  #define __glibcxx_want_constexpr_char_traits
>  #define __glibcxx_want_constexpr_string
> @@ -105,7 +106,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        return __osz - __cont.size();
>      }
>  
> -  template<typename _CharT, typename _Traits, typename _Alloc, typename _Up>
> +  template<typename _CharT, typename _Traits, typename _Alloc, typename _Up
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_CharT)>
>      _GLIBCXX20_CONSTEXPR
>      inline typename basic_string<_CharT, _Traits, _Alloc>::size_type
>      erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value)
> diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector
> index 906c1627935..60a21bd92d1 100644
> --- a/libstdc++-v3/include/std/vector
> +++ b/libstdc++-v3/include/std/vector
> @@ -76,6 +76,7 @@
>  # include <debug/vector>
>  #endif
>  
> +#define __glibcxx_want_algorithm_default_value_type
>  #define __glibcxx_want_allocator_traits_is_always_equal
>  #define __glibcxx_want_constexpr_vector
>  #define __glibcxx_want_erase_if
> @@ -129,7 +130,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        return 0;
>      }
>  
> -  template<typename _Tp, typename _Alloc, typename _Up>
> +  template<typename _Tp, typename _Alloc, typename _Up
> +        _GLIBCXX26_ALGORITHM_DEFAULT_VALUE_TYPE(_Tp)>
>      _GLIBCXX20_CONSTEXPR
>      inline typename vector<_Tp, _Alloc>::size_type
>      erase(vector<_Tp, _Alloc>& __cont, const _Up& __value)
> diff --git a/libstdc++-v3/testsuite/23_containers/default_template_value.cc 
> b/libstdc++-v3/testsuite/23_containers/default_template_value.cc
> new file mode 100644
> index 00000000000..b7615032686
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/default_template_value.cc
> @@ -0,0 +1,40 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <deque>
> +#include <forward_list>
> +#include <list>
> +#include <string>
> +#include <vector>
> +
> +#if !defined(__cpp_lib_algorithm_default_value_type)
> +#error "Feature test macro for default template type for algorithms' values 
> is missing"
> +#elif __cpp_lib_algorithm_default_value_type < 202403L
> +#error "Feature test macro for default template type for algorithms' values 
> is wrong"
> +#endif
> +
> +struct S {
> +  S(int, double);
> +  friend auto operator<=>(const S&, const S&) = default;
> +};
> +
> +template<template<typename...> typename Container>
> +void test_erase()
> +{
> +  Container<S> c;
> +  std::erase(c, {1, 3.14});
> +}
> +
> +void
> +test()
> +{
> +  test_erase<std::deque>();
> +  test_erase<std::forward_list>();
> +  test_erase<std::list>();
> +  test_erase<std::vector>();
> +
> +  std::string s;
> +  std::erase(s, {'x'});
> +
> +  std::wstring ws;
> +  std::erase(ws, {L'x'});
> +}
> diff --git a/libstdc++-v3/testsuite/25_algorithms/default_template_value.cc 
> b/libstdc++-v3/testsuite/25_algorithms/default_template_value.cc
> new file mode 100644
> index 00000000000..3cf51bc087b
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/25_algorithms/default_template_value.cc
> @@ -0,0 +1,142 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <algorithm>
> +
> +#if !defined(__cpp_lib_algorithm_default_value_type)
> +#error "Feature test macro for default template type for algorithms' values 
> is missing"
> +#elif __cpp_lib_algorithm_default_value_type < 202403L
> +#error "Feature test macro for default template type for algorithms' values 
> is wrong"
> +#endif
> +
> +#include <execution>
> +#include <ranges>
> +#include <iterator>
> +#include <vector>
> +
> +// Conversions from Input to Output will be used in certain algorithms.
> +// Make Output have a different number of arguments to its constructor
> +// so we can check whether a braced-init-list is indeed matching Input
> +// or Output
> +struct Output
> +{
> +  Output(char, float, long);
> +};
> +
> +#define OUTPUT_VAL {'x', 1.171f, 10L}
> +
> +struct Input
> +{
> +  Input(int, double);
> +  friend bool operator<=>(const Input &, const Input &) = default;
> +  friend Input operator+(const Input &, const Input &);
> +  operator Output() const;
> +};
> +
> +#define INPUT_VAL {1, 3.14}
> +
> +void
> +test()
> +{
> +  extern std::vector<Input> in;
> +  extern std::vector<Output> out;
> +
> +  const auto pred = [](auto &&) { return true; };
> +
> +  // [alg.find]
> +  (void) std::find(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::find(std::execution::seq, in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::find(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::find(in, INPUT_VAL);
> +
> +  // [alg.count]
> +  (void) std::count(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::count(std::execution::seq, in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::count(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::count(in, INPUT_VAL);
> +
> +  // [alg.search]
> +  (void) std::search_n(in.begin(), in.end(), 10, INPUT_VAL);
> +  (void) std::search_n(in.begin(), in.end(), 10, INPUT_VAL, std::equal_to{});
> +  (void) std::search_n(std::execution::seq, in.begin(), in.end(), 10, 
> INPUT_VAL);
> +  (void) std::search_n(std::execution::seq, in.begin(), in.end(), 10, 
> INPUT_VAL, std::equal_to{});
> +  (void) std::ranges::search_n(in.begin(), in.end(), 10, INPUT_VAL);
> +  (void) std::ranges::search_n(in, 10, INPUT_VAL);
> +
> +  // [alg.replace]
> +  (void) std::replace(in.begin(), in.end(), INPUT_VAL, INPUT_VAL);
> +  (void) std::replace(std::execution::seq, in.begin(), in.end(), INPUT_VAL, 
> INPUT_VAL);
> +  (void) std::replace_if(in.begin(), in.end(), pred, INPUT_VAL);
> +  (void) std::replace_if(std::execution::seq, in.begin(), in.end(), pred, 
> INPUT_VAL);
> +
> +  (void) std::ranges::replace(in.begin(), in.end(), INPUT_VAL, INPUT_VAL);
> +  (void) std::ranges::replace(in, INPUT_VAL, INPUT_VAL);
> +  (void) std::ranges::replace_if(in.begin(), in.end(), pred, INPUT_VAL);
> +  (void) std::ranges::replace_if(in, pred, INPUT_VAL);
> +
> +  (void) std::replace_copy_if(in.begin(), in.end(), out.begin(), pred, 
> OUTPUT_VAL);
> +  (void) std::replace_copy_if(std::execution::seq, in.begin(), in.end(), 
> out.begin(), pred, OUTPUT_VAL);
> +  (void) std::ranges::replace_copy_if(in.begin(), in.end(), out.begin(), 
> pred, OUTPUT_VAL);
> +  (void) std::ranges::replace_copy_if(in, out.begin(), pred, OUTPUT_VAL);
> +
> +  // Non-range replace_copy is deliberately skipped by P2248
> +  (void) std::ranges::replace_copy(in.begin(), in.end(), out.begin(), 
> INPUT_VAL, OUTPUT_VAL);
> +  (void) std::ranges::replace_copy(in, out.begin(), INPUT_VAL, OUTPUT_VAL);
> +
> +  // [alg.fill]
> +  (void) std::fill(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::fill(std::execution::seq, in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::fill(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::fill(in, INPUT_VAL);
> +
> +  (void) std::fill_n(in.begin(), 10, INPUT_VAL);
> +  (void) std::fill_n(std::execution::seq, in.begin(), 10, INPUT_VAL);
> +  (void) std::ranges::fill_n(in.begin(), 10, INPUT_VAL);
> +
> +  // [alg.remove]
> +  (void) std::remove(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::remove(std::execution::seq, in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::remove(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::remove(in, INPUT_VAL);
> +
> +  (void) std::remove_copy(in.begin(), in.end(), out.begin(), INPUT_VAL);
> +  (void) std::remove_copy(std::execution::seq, in.begin(), in.end(), 
> out.begin(), INPUT_VAL);
> +  (void) std::ranges::remove_copy(in.begin(), in.end(), out.begin(), 
> INPUT_VAL);
> +  (void) std::ranges::remove_copy(in, out.begin(), INPUT_VAL);
> +
> +  // [alg.binary.search]
> +  (void) std::lower_bound(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::lower_bound(in.begin(), in.end(), INPUT_VAL, std::less{});
> +  (void) std::ranges::lower_bound(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::lower_bound(in, INPUT_VAL);
> +
> +  (void) std::upper_bound(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::upper_bound(in.begin(), in.end(), INPUT_VAL, std::less{});
> +  (void) std::ranges::upper_bound(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::upper_bound(in, INPUT_VAL);
> +
> +  (void) std::equal_range(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::equal_range(in.begin(), in.end(), INPUT_VAL, std::less{});
> +  (void) std::ranges::equal_range(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::equal_range(in, INPUT_VAL);
> +
> +  (void) std::binary_search(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::binary_search(in.begin(), in.end(), INPUT_VAL, std::less{});
> +  (void) std::ranges::binary_search(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::binary_search(in, INPUT_VAL);
> +
> +  // [alg.fold]
> +  (void) std::ranges::fold_left(in.begin(), in.end(), INPUT_VAL, 
> std::plus<>{});
> +  (void) std::ranges::fold_left(in, INPUT_VAL, std::plus<>{});
> +  (void) std::ranges::fold_right(in.begin(), in.end(), INPUT_VAL, 
> std::plus<>{});
> +  (void) std::ranges::fold_right(in, INPUT_VAL, std::plus<>{});
> +  (void) std::ranges::fold_left_with_iter(in.begin(), in.end(), INPUT_VAL, 
> std::plus<>{});
> +  (void) std::ranges::fold_left_with_iter(in, INPUT_VAL, std::plus<>{});
> +
> +  // [alg.contains]
> +  (void) std::ranges::contains(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::contains(in, INPUT_VAL);
> +
> +  // [alg.find.last]
> +  (void) std::ranges::find_last(in.begin(), in.end(), INPUT_VAL);
> +  (void) std::ranges::find_last(in, INPUT_VAL);
> +}

Reply via email to