On Fri, 13 Sep 2024, Patrick Palka wrote: > 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>&>>;
Ah, we very recently implemented P2609R3 which has the following note about projected_value_t: https://wg21.link/p2609r3#proposal Do we want to honor this note here and define projected_value_t as remove_cvref_t<__indirect_value_t<_Iter>> then? It seems the working draft doesn't define it that way despite having merged both these papers. > > +#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); > > +} >