libstdc++: add default template parameters to algorithms

Message ID e91d6e4f-69c9-432d-ab0c-59a8f720edd6@kdab.com
State New
Headers
Series libstdc++: add default template parameters to algorithms |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply

Commit Message

Giuseppe D'Angelo Aug. 2, 2024, 10:44 a.m. UTC
  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.

Thanks,

-- 
Giuseppe D'Angelo
  

Comments

Jonathan Wakely Aug. 2, 2024, 12:17 p.m. UTC | #1
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.

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.

I think there's a misunderstanding about how this works:
+#define __glibcxx_want_default_template_type_for_algorithm_values
+#include <bits/version.h>

For every standard __cpp_lib_foo feature test macro there is also an
internal __glibcxx_foo macro. The standard __cpp_lib_foo one should
*only* be defined in the headers that the standard documents to define
the macro (and in <version>, which happens automatically). That
happens when you define __glibcxx_want_foo before including
<bits/version.h>, so that must only be done in the standard headers
that should define the __cpp_lib_foo version.

For this feature, the standard says:
#define __cpp_lib_default_template_type_for_algorithm_values YYYYMML  // also in
    // <algorithm>, <ranges>,
    // <string>, <deque>, <list>, <forward_list>, <vector>
So you should put the __glibcxx_want_xxx macro in the headers named
above, but directly in the standard <vector> header (and <string>,
etc.) not in <bits/stl_vector.h> or any other internal detail headers.

It's wrong to use __glibcxx_want_foo in <bits/ranges_algo.h> and in
your new header.
The internal headers like <bits/ranges_algo.h> should use the
__glibcxx_foo macro, not the __cpp_lib_foo one. The __glibcxx_foo one
is defined without the "want" macro, so is always defined when the
feature is supported. That means you can test the __glibcxx_foo macro
after including <bits/version.h> *without* saying you "want" the
standard __cpp_lib_foo macro.

I don't think that stuff is documented yet, so I'll put something like
the text above into the manual.

Minor comments:

+#if __glibcxx_default_template_type_for_algorithm_values // 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

Please add a line break before the '=' to keep this line shorter.

+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+         typename _Proj = identity, typename _Tp =
projected_value_t<_Iter, _Proj>>
+#else

And a line break after 'identity,' here please.


The new header has incorrect copyright info:
+// Copyright (C) 2007-2024 Free Software Foundation, Inc.
The dates are wrong, and you're contributing it under the DCO so
please use this form (with no dates):
// Copyright The GNU Toolchain Authors.
This is what I've been doing for all new files I add over the last few years.
The GPL and warranty text should remain, just change the copyright line.

**BUT** I don't think we should add a new header just for that anyway.
Hitting the filesystem to open a new header has a cost, and it's just
defining one macro anyway.
Could the macro just go in <bits/stl_iterator.h> ? Or stl_iterator_base_types?
Normally I'd say to put that kind of widely-used macro in
<bits/c++config.h> but that doesn't work here because it depends on
the feature test macro in <bits/version.h> which is included later.
  
Jonathan Wakely Aug. 2, 2024, 12:38 p.m. UTC | #2
On Fri, 2 Aug 2024 at 13:17, Jonathan Wakely <jwakely@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.
>
> 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.
>
> I think there's a misunderstanding about how this works:
> +#define __glibcxx_want_default_template_type_for_algorithm_values
> +#include <bits/version.h>
>
> For every standard __cpp_lib_foo feature test macro there is also an
> internal __glibcxx_foo macro. The standard __cpp_lib_foo one should
> *only* be defined in the headers that the standard documents to define
> the macro (and in <version>, which happens automatically). That
> happens when you define __glibcxx_want_foo before including
> <bits/version.h>, so that must only be done in the standard headers
> that should define the __cpp_lib_foo version.
>
> For this feature, the standard says:
> #define __cpp_lib_default_template_type_for_algorithm_values YYYYMML  // also in
>     // <algorithm>, <ranges>,
>     // <string>, <deque>, <list>, <forward_list>, <vector>
> So you should put the __glibcxx_want_xxx macro in the headers named
> above, but directly in the standard <vector> header (and <string>,
> etc.) not in <bits/stl_vector.h> or any other internal detail headers.
>
> It's wrong to use __glibcxx_want_foo in <bits/ranges_algo.h> and in
> your new header.
> The internal headers like <bits/ranges_algo.h> should use the
> __glibcxx_foo macro, not the __cpp_lib_foo one. The __glibcxx_foo one
> is defined without the "want" macro, so is always defined when the
> feature is supported. That means you can test the __glibcxx_foo macro
> after including <bits/version.h> *without* saying you "want" the
> standard __cpp_lib_foo macro.
>
> I don't think that stuff is documented yet, so I'll put something like
> the text above into the manual.

Oh also, the editor renamed the feature test macro to
__cpp_lib_algorithm_default_value_type so it fits on the page ;-)
Your patch should use that, not the one in the proposal.

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.
  
Giuseppe D'Angelo Aug. 2, 2024, 10:49 p.m. UTC | #3
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 <jwakely@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.

Thanks,
-- 
Giuseppe D'Angelo
  
Jonathan Wakely Aug. 2, 2024, 11:10 p.m. UTC | #4
On Fri, 2 Aug 2024 at 23:49, Giuseppe D'Angelo
<giuseppe.dangelo@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 <jwakely@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 <jwakely@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.
  

Patch

From 9f1a84548ecea9859c1f8d70c533e4e5a0701870 Mon Sep 17 00:00:00 2001
From: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Date: Fri, 2 Aug 2024 00:23:04 +0200
Subject: [PATCH] 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, the change is simple and localized enough to justify
an ifdef on the feature testing macro;

* for "classic" algorithms and the parallel versions, introduce a
dedicated macro;

* range algorithms are more tricky as they usually require reordering
of the template parameters, and sometimes the introduction of new
constraints. The idea was to avoid too much surgery and try and keep
the code clean w.r.t. the pre-P2248 versions, even if sometimes this
means duplicating the template heads.

libstdc++-v3/ChangeLog:

	* include/Makefile.am: Add the new header.
	* include/Makefile.in: Regenerate.
	* 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/version.def: Add the new feature-testing macro.
	* include/bits/version.h (defined): 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.
	* include/bits/stl_algorithm_default.h: New file. Adds a macro
	to help with adding the default to the "classic STL" algorithms.
	* 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.dangelo@kdab.com>
---
 libstdc++-v3/include/Makefile.am              |   1 +
 libstdc++-v3/include/Makefile.in              |   1 +
 libstdc++-v3/include/bits/algorithmfwd.h      |  62 +++--
 libstdc++-v3/include/bits/iterator_concepts.h |   9 +
 libstdc++-v3/include/bits/ranges_algo.h       | 227 ++++++++++++++++--
 libstdc++-v3/include/bits/ranges_algobase.h   |  20 ++
 libstdc++-v3/include/bits/ranges_util.h       |  13 +
 .../include/bits/stl_algorithm_default.h      |  45 ++++
 libstdc++-v3/include/bits/version.def         |   8 +
 libstdc++-v3/include/bits/version.h           |  10 +
 .../include/pstl/glue_algorithm_defs.h        |  23 +-
 libstdc++-v3/include/std/algorithm            |   1 +
 libstdc++-v3/include/std/deque                |   7 +-
 libstdc++-v3/include/std/forward_list         |   7 +-
 libstdc++-v3/include/std/list                 |   7 +-
 libstdc++-v3/include/std/ranges               |   1 +
 libstdc++-v3/include/std/string               |   7 +-
 libstdc++-v3/include/std/vector               |   7 +-
 .../23_containers/default_template_value.cc   |  40 +++
 .../25_algorithms/default_template_value.cc   | 142 +++++++++++
 20 files changed, 589 insertions(+), 49 deletions(-)
 create mode 100644 libstdc++-v3/include/bits/stl_algorithm_default.h
 create mode 100644 libstdc++-v3/testsuite/23_containers/default_template_value.cc
 create mode 100644 libstdc++-v3/testsuite/25_algorithms/default_template_value.cc

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 422a0f4bd0a..9da3f930dba 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -149,6 +149,7 @@  bits_freestanding = \
 	${bits_srcdir}/sat_arith.h \
 	${bits_srcdir}/stl_algo.h \
 	${bits_srcdir}/stl_algobase.h \
+	${bits_srcdir}/stl_algorithm_default.h \
 	${bits_srcdir}/stl_construct.h \
 	${bits_srcdir}/stl_function.h \
 	${bits_srcdir}/stl_iterator.h \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 9fd4ab4848c..2f39f484ab6 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -504,6 +504,7 @@  bits_freestanding = \
 	${bits_srcdir}/sat_arith.h \
 	${bits_srcdir}/stl_algo.h \
 	${bits_srcdir}/stl_algobase.h \
+	${bits_srcdir}/stl_algorithm_default.h \
 	${bits_srcdir}/stl_construct.h \
 	${bits_srcdir}/stl_function.h \
 	${bits_srcdir}/stl_iterator.h \
diff --git a/libstdc++-v3/include/bits/algorithmfwd.h b/libstdc++-v3/include/bits/algorithmfwd.h
index 34bf9921f43..2b93f35985f 100644
--- a/libstdc++-v3/include/bits/algorithmfwd.h
+++ b/libstdc++-v3/include/bits/algorithmfwd.h
@@ -33,6 +33,7 @@ 
 #pragma GCC system_header
 
 #include <bits/c++config.h>
+#include <bits/stl_algorithm_default.h>
 #include <bits/stl_pair.h>
 #include <bits/stl_iterator_base_types.h>
 #if __cplusplus >= 201103L
@@ -203,12 +204,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     any_of(_IIter, _IIter, _Predicate);
 #endif
 
-  template<typename _FIter, typename _Tp>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter)>
     _GLIBCXX20_CONSTEXPR
     bool
     binary_search(_FIter, _FIter, const _Tp&);
 
-  template<typename _FIter, typename _Tp, typename _Compare>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter),
+	   typename _Compare>
     _GLIBCXX20_CONSTEXPR
     bool
     binary_search(_FIter, _FIter, const _Tp&, _Compare);
@@ -250,22 +254,27 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // count
   // count_if
 
-  template<typename _FIter, typename _Tp>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter)>
     _GLIBCXX20_CONSTEXPR
     void
     fill(_FIter, _FIter, const _Tp&);
 
-  template<typename _OIter, typename _Size, typename _Tp>
+  template<typename _OIter, typename _Size, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_OIter)>
     _GLIBCXX20_CONSTEXPR
     _OIter
     fill_n(_OIter, _Size, const _Tp&);
@@ -377,12 +386,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     void
     iter_swap(_FIter1, _FIter2);
 
-  template<typename _FIter, typename _Tp>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter)>
     _GLIBCXX20_CONSTEXPR
     _FIter
     lower_bound(_FIter, _FIter, const _Tp&);
 
-  template<typename _FIter, typename _Tp, typename _Compare>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter),
+	   typename _Compare>
     _GLIBCXX20_CONSTEXPR
     _FIter
     lower_bound(_FIter, _FIter, const _Tp&, _Compare);
@@ -553,7 +565,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // random_shuffle
 
-  template<typename _FIter, typename _Tp>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter)>
     _GLIBCXX20_CONSTEXPR
     _FIter
     remove(_FIter, _FIter, const _Tp&);
@@ -563,7 +576,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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_IIter)>
     _GLIBCXX20_CONSTEXPR
     _OIter
     remove_copy(_IIter, _IIter, _OIter, const _Tp&);
@@ -580,7 +594,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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_OIter)>
     _GLIBCXX20_CONSTEXPR
     _OIter
     replace_copy_if(_Iter, _Iter, _OIter, _Predicate, const _Tp&);
@@ -673,12 +688,15 @@  _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
 
   // unique_copy
 
-  template<typename _FIter, typename _Tp>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter)>
     _GLIBCXX20_CONSTEXPR
     _FIter
     upper_bound(_FIter, _FIter, const _Tp&);
 
-  template<typename _FIter, typename _Tp, typename _Compare>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter),
+	   typename _Compare>
     _GLIBCXX20_CONSTEXPR
     _FIter
     upper_bound(_FIter, _FIter, const _Tp&, _Compare);
@@ -695,7 +713,8 @@  _GLIBCXX_BEGIN_NAMESPACE_ALGO
     _FIter
     adjacent_find(_FIter, _FIter, _BinaryPredicate);
 
-  template<typename _IIter, typename _Tp>
+  template<typename _IIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_IIter)>
     _GLIBCXX20_CONSTEXPR
     typename iterator_traits<_IIter>::difference_type
     count(_IIter, _IIter, const _Tp&);
@@ -715,7 +734,8 @@  _GLIBCXX_BEGIN_NAMESPACE_ALGO
     bool
     equal(_IIter1, _IIter1, _IIter2, _BinaryPredicate);
 
-  template<typename _IIter, typename _Tp>
+  template<typename _IIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_IIter)>
     _GLIBCXX20_CONSTEXPR
     _IIter
     find(_IIter, _IIter, const _Tp&);
@@ -843,12 +863,14 @@  _GLIBCXX_BEGIN_NAMESPACE_ALGO
 #endif
 #endif // HOSTED
 
-  template<typename _FIter, typename _Tp>
+  template<typename _FIter, typename _Tp
+	   _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_FIter)>
     _GLIBCXX20_CONSTEXPR
     void
     replace_if(_FIter, _FIter, _Predicate, const _Tp&);
@@ -863,12 +885,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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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 ce0b8a10f88..47e19514465 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -37,6 +37,9 @@ 
 #include <bits/ptr_traits.h>	// to_address
 #include <bits/ranges_cmp.h>	// identity, ranges::less
 
+#define __glibcxx_want_default_template_type_for_algorithm_values
+#include <bits/version.h>
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -799,6 +802,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	   indirectly_regular_unary_invocable<_Iter> _Proj>
     using projected = typename __detail::__projected<_Iter, _Proj>::__type;
 
+#if __glibcxx_default_template_type_for_algorithm_values // 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..90d0932656e 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -39,6 +39,9 @@ 
 #include <bits/ranges_util.h>
 #include <bits/uniform_int_dist.h> // concept uniform_random_bit_generator
 
+#define __glibcxx_want_default_template_type_for_algorithm_values
+#include <bits/version.h>
+
 #if __glibcxx_concepts
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -280,8 +283,13 @@  namespace ranges
 
   struct __count_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Proj = identity, typename _Tp = projected_value_t<_Iter, _Proj>>
+#else
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Tp, typename _Proj = identity>
+#endif
       requires indirect_binary_predicate<ranges::equal_to,
 					 projected<_Iter, _Proj>,
 					 const _Tp*>
@@ -296,7 +304,12 @@  namespace ranges
 	return __n;
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_range _Range, typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>>
+#else
     template<input_range _Range, typename _Tp, typename _Proj = identity>
+#endif
       requires indirect_binary_predicate<ranges::equal_to,
 					 projected<iterator_t<_Range>, _Proj>,
 					 const _Tp*>
@@ -344,8 +357,14 @@  namespace ranges
 
   struct __search_n_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Pred = ranges::equal_to, typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>>
+#else
     template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
 	     typename _Pred = ranges::equal_to, typename _Proj = identity>
+#endif
       requires indirectly_comparable<_Iter, const _Tp*, _Pred, _Proj>
       constexpr subrange<_Iter>
       operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __count,
@@ -416,8 +435,14 @@  namespace ranges
 	  }
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<forward_range _Range,
+	     typename _Pred = ranges::equal_to, typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>>
+#else
     template<forward_range _Range, typename _Tp,
 	     typename _Pred = ranges::equal_to, typename _Proj = identity>
+#endif
       requires indirectly_comparable<iterator_t<_Range>, const _Tp*,
 				     _Pred, _Proj>
       constexpr borrowed_subrange_t<_Range>
@@ -773,8 +798,15 @@  namespace ranges
 
   struct __replace_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Proj = identity,
+	     typename _Tp1 = projected_value_t<_Iter, _Proj>,
+	     typename _Tp2 = _Tp1>
+#else
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Tp1, typename _Tp2, typename _Proj = identity>
+#endif
       requires indirectly_writable<_Iter, const _Tp2&>
 	&& indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>,
 				     const _Tp1*>
@@ -789,8 +821,14 @@  namespace ranges
 	return __first;
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_range _Range, typename _Proj = identity,
+	     typename _Tp1 = projected_value_t<iterator_t<_Range>, _Proj>,
+	     typename _Tp2 = _Tp1>
+#else
     template<input_range _Range,
 	     typename _Tp1, typename _Tp2, typename _Proj = identity>
+#endif
       requires indirectly_writable<iterator_t<_Range>, const _Tp2&>
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<iterator_t<_Range>, _Proj>,
@@ -809,9 +847,16 @@  namespace ranges
 
   struct __replace_if_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>,
+	     indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
+#else
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Tp, typename _Proj = identity,
 	     indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
+#endif
       requires indirectly_writable<_Iter, const _Tp&>
       constexpr _Iter
       operator()(_Iter __first, _Sent __last,
@@ -823,9 +868,16 @@  namespace ranges
 	return std::move(__first);
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_range _Range, typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>,
+	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
+	       _Pred>
+#else
     template<input_range _Range, typename _Tp, typename _Proj = identity,
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
+#endif
       requires indirectly_writable<iterator_t<_Range>, const _Tp&>
       constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r,
@@ -843,12 +895,22 @@  namespace ranges
 
   struct __replace_copy_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Out, typename _Proj = identity,
+	     typename _Tp1 = projected_value_t<_Iter, _Proj>,
+	     typename _Tp2 = iter_value_t<_Out>>
+#else
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Tp1, typename _Tp2, output_iterator<const _Tp2&> _Out,
 	     typename _Proj = identity>
+#endif
       requires indirectly_copyable<_Iter, _Out>
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<_Iter, _Proj>, const _Tp1*>
+#if __glibcxx_default_template_type_for_algorithm_values
+	&& output_iterator<_Out, const _Tp2&>
+#endif
       constexpr replace_copy_result<_Iter, _Out>
       operator()(_Iter __first, _Sent __last, _Out __result,
 		 const _Tp1& __old_value, const _Tp2& __new_value,
@@ -862,12 +924,22 @@  namespace ranges
 	return {std::move(__first), std::move(__result)};
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_range _Range, typename _Out,
+	     typename _Proj = identity,
+	     typename _Tp1 = projected_value_t<iterator_t<_Range>, _Proj>,
+	     typename _Tp2 = iter_value_t<_Out>>
+#else
     template<input_range _Range, typename _Tp1, typename _Tp2,
 	     output_iterator<const _Tp2&> _Out, typename _Proj = identity>
+#endif
       requires indirectly_copyable<iterator_t<_Range>, _Out>
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<iterator_t<_Range>, _Proj>,
 				     const _Tp1*>
+#if __glibcxx_default_template_type_for_algorithm_values
+	&& output_iterator<_Out, const _Tp2&>
+#endif
       constexpr replace_copy_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result,
 		 const _Tp1& __old_value, const _Tp2& __new_value,
@@ -886,11 +958,21 @@  namespace ranges
 
   struct __replace_copy_if_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Out, typename _Tp = iter_value_t<_Out>,
+	     typename _Proj = identity,
+	     indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
+#else
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Tp, output_iterator<const _Tp&> _Out,
 	     typename _Proj = identity,
 	     indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
+#endif
       requires indirectly_copyable<_Iter, _Out>
+#if __glibcxx_default_template_type_for_algorithm_values
+	&& output_iterator<_Out, const _Tp&>
+#endif
       constexpr replace_copy_if_result<_Iter, _Out>
       operator()(_Iter __first, _Sent __last, _Out __result,
 		 _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) const
@@ -903,12 +985,23 @@  namespace ranges
 	return {std::move(__first), std::move(__result)};
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_range _Range,
+	     typename _Out, typename _Tp = iter_value_t<_Out>,
+	     typename _Proj = identity,
+	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
+	       _Pred>
+#else
     template<input_range _Range,
 	     typename _Tp, output_iterator<const _Tp&> _Out,
 	     typename _Proj = identity,
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
+#endif
       requires indirectly_copyable<iterator_t<_Range>, _Out>
+#if __glibcxx_default_template_type_for_algorithm_values
+	&& output_iterator<_Out, const _Tp&>
+#endif
       constexpr replace_copy_if_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result,
 		 _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) const
@@ -1003,8 +1096,14 @@  namespace ranges
 
   struct __remove_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<permutable _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>>
+#else
     template<permutable _Iter, sentinel_for<_Iter> _Sent,
 	     typename _Tp, typename _Proj = identity>
+#endif
       requires indirect_binary_predicate<ranges::equal_to,
 					 projected<_Iter, _Proj>,
 					 const _Tp*>
@@ -1019,7 +1118,12 @@  namespace ranges
 				 std::move(__pred), std::move(__proj));
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<forward_range _Range, typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>>
+#else
     template<forward_range _Range, typename _Tp, typename _Proj = identity>
+#endif
       requires permutable<iterator_t<_Range>>
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<iterator_t<_Range>, _Proj>,
@@ -1078,8 +1182,14 @@  namespace ranges
 
   struct __remove_copy_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     weakly_incrementable _Out, typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>>
+#else
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	     weakly_incrementable _Out, typename _Tp, typename _Proj = identity>
+#endif
       requires indirectly_copyable<_Iter, _Out>
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<_Iter, _Proj>,
@@ -1097,8 +1207,14 @@  namespace ranges
 	return {std::move(__first), std::move(__result)};
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_range _Range, weakly_incrementable _Out,
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>>
+#else
     template<input_range _Range, weakly_incrementable _Out,
 	     typename _Tp, typename _Proj = identity>
+#endif
       requires indirectly_copyable<iterator_t<_Range>, _Out>
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<iterator_t<_Range>, _Proj>,
@@ -2047,7 +2163,12 @@  namespace ranges
   struct __lower_bound_fn
   {
     template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+#if __glibcxx_default_template_type_for_algorithm_values
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>,
+#else
 	     typename _Tp, typename _Proj = identity,
+#endif
 	     indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
 	       _Comp = ranges::less>
       constexpr _Iter
@@ -2073,7 +2194,13 @@  namespace ranges
 	return __first;
       }
 
-    template<forward_range _Range, typename _Tp, typename _Proj = identity,
+    template<forward_range _Range,
+#if __glibcxx_default_template_type_for_algorithm_values
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>,
+#else
+	     typename _Tp, typename _Proj = identity,
+#endif
 	     indirect_strict_weak_order<const _Tp*,
 					projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
@@ -2091,7 +2218,12 @@  namespace ranges
   struct __upper_bound_fn
   {
     template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+#if __glibcxx_default_template_type_for_algorithm_values
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>,
+#else
 	     typename _Tp, typename _Proj = identity,
+#endif
 	     indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
 	       _Comp = ranges::less>
       constexpr _Iter
@@ -2117,7 +2249,13 @@  namespace ranges
 	return __first;
       }
 
-    template<forward_range _Range, typename _Tp, typename _Proj = identity,
+    template<forward_range _Range,
+#if __glibcxx_default_template_type_for_algorithm_values
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>,
+#else
+	     typename _Tp, typename _Proj = identity,
+#endif
 	     indirect_strict_weak_order<const _Tp*,
 					projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
@@ -2135,7 +2273,12 @@  namespace ranges
   struct __equal_range_fn
   {
     template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+#if __glibcxx_default_template_type_for_algorithm_values
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>,
+#else
 	     typename _Tp, typename _Proj = identity,
+#endif
 	     indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
 	       _Comp = ranges::less>
       constexpr subrange<_Iter>
@@ -2177,7 +2320,12 @@  namespace ranges
       }
 
     template<forward_range _Range,
+#if __glibcxx_default_template_type_for_algorithm_values
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>,
+#else
 	     typename _Tp, typename _Proj = identity,
+#endif
 	     indirect_strict_weak_order<const _Tp*,
 					projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
@@ -2195,7 +2343,12 @@  namespace ranges
   struct __binary_search_fn
   {
     template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+#if __glibcxx_default_template_type_for_algorithm_values
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>,
+#else
 	     typename _Tp, typename _Proj = identity,
+#endif
 	     indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
 	       _Comp = ranges::less>
       constexpr bool
@@ -2210,7 +2363,12 @@  namespace ranges
       }
 
     template<forward_range _Range,
+#if __glibcxx_default_template_type_for_algorithm_values
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>,
+#else
 	     typename _Tp, typename _Proj = identity,
+#endif
 	     indirect_strict_weak_order<const _Tp*,
 					projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
@@ -3468,15 +3626,27 @@  namespace ranges
 #if __glibcxx_ranges_contains >= 202207L // C++ >= 23
   struct __contains_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+	    typename _Proj = identity,
+	    typename _Tp = projected_value_t<_Iter, _Proj>>
+#else
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
 	    typename _Tp, typename _Proj = identity>
+#endif
       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; }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_range _Range,
+	    typename _Proj = identity,
+	    typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>>
+#else
     template<input_range _Range, typename _Tp, typename _Proj = identity>
+#endif
       requires indirect_binary_predicate<ranges::equal_to,
 					 projected<iterator_t<_Range>, _Proj>, const _Tp*>
       constexpr bool
@@ -3525,7 +3695,13 @@  namespace ranges
 
   struct __find_last_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Proj = identity,
+	     typename _Tp = projected_value_t<_Iter, _Proj>>
+#else
     template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp, typename _Proj = identity>
+#endif
       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 +3732,12 @@  namespace ranges
 	  }
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<forward_range _Range, typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>>
+#else
     template<forward_range _Range, typename _Tp, typename _Proj = identity>
+#endif
       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,8 +3911,11 @@  namespace ranges
 	return _Ret{std::move(__first), std::move(__accum)};
       }
 
-    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
-	     __detail::__indirectly_binary_left_foldable<_Tp, _Iter> _Fp>
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp
+#if __glibcxx_default_template_type_for_algorithm_values
+	     = iter_value_t<_Iter>
+#endif
+	     , __detail::__indirectly_binary_left_foldable<_Tp, _Iter> _Fp>
       constexpr auto
       operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
       {
@@ -3740,8 +3924,11 @@  namespace ranges
 				  std::move(__init), std::move(__f));
       }
 
-    template<input_range _Range, typename _Tp,
-	     __detail::__indirectly_binary_left_foldable<_Tp, iterator_t<_Range>> _Fp>
+    template<input_range _Range, typename _Tp
+#if __glibcxx_default_template_type_for_algorithm_values
+	     = range_value_t<_Range>
+#endif
+	     , __detail::__indirectly_binary_left_foldable<_Tp, iterator_t<_Range>> _Fp>
       constexpr auto
       operator()(_Range&& __r, _Tp __init, _Fp __f) const
       {
@@ -3755,8 +3942,11 @@  namespace ranges
 
   struct __fold_left_fn
   {
-    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
-	     __detail::__indirectly_binary_left_foldable<_Tp, _Iter> _Fp>
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp
+#if __glibcxx_default_template_type_for_algorithm_values
+	     = iter_value_t<_Iter>
+#endif
+	     , __detail::__indirectly_binary_left_foldable<_Tp, _Iter> _Fp>
       constexpr auto
       operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
       {
@@ -3764,8 +3954,11 @@  namespace ranges
 					   std::move(__init), std::move(__f)).value;
       }
 
-    template<input_range _Range, typename _Tp,
-	     __detail::__indirectly_binary_left_foldable<_Tp, iterator_t<_Range>> _Fp>
+    template<input_range _Range, typename _Tp
+#if __glibcxx_default_template_type_for_algorithm_values
+	     = range_value_t<_Range>
+#endif
+	     , __detail::__indirectly_binary_left_foldable<_Tp, iterator_t<_Range>> _Fp>
       constexpr auto
       operator()(_Range&& __r, _Tp __init, _Fp __f) const
       { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__init), std::move(__f)); }
@@ -3842,8 +4035,11 @@  namespace ranges
 
   struct __fold_right_fn
   {
-    template<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
-	     __detail::__indirectly_binary_right_foldable<_Tp, _Iter> _Fp>
+    template<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp
+#if __glibcxx_default_template_type_for_algorithm_values
+	     = iter_value_t<_Iter>
+#endif
+	     , __detail::__indirectly_binary_right_foldable<_Tp, _Iter> _Fp>
       constexpr auto
       operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
       {
@@ -3859,8 +4055,11 @@  namespace ranges
 	return __accum;
       }
 
-    template<bidirectional_range _Range, typename _Tp,
-	     __detail::__indirectly_binary_right_foldable<_Tp, iterator_t<_Range>> _Fp>
+    template<bidirectional_range _Range, typename _Tp
+#if __glibcxx_default_template_type_for_algorithm_values
+	     = range_value_t<_Range>
+#endif
+	     , __detail::__indirectly_binary_right_foldable<_Tp, iterator_t<_Range>> _Fp>
       constexpr auto
       operator()(_Range&& __r, _Tp __init, _Fp __f) const
       { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__init), std::move(__f)); }
diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index fd35b8ba14c..2b7eb74029f 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -40,6 +40,9 @@ 
 #include <bits/cpp_type_traits.h> // __is_byte
 #include <bits/stl_algobase.h> // __memcmp
 
+#define __glibcxx_want_default_template_type_for_algorithm_values
+#include <bits/version.h>
+
 #if __cpp_lib_concepts
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -536,7 +539,12 @@  namespace ranges
 
   struct __fill_n_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<typename _Out, typename _Tp = iter_value_t<_Out>>
+      requires output_iterator<_Out, const _Tp&>
+#else
     template<typename _Tp, output_iterator<const _Tp&> _Out>
+#endif
       constexpr _Out
       operator()(_Out __first, iter_difference_t<_Out> __n,
 		 const _Tp& __value) const
@@ -581,8 +589,15 @@  namespace ranges
 
   struct __fill_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<typename _Out,
+	     sentinel_for<_Out> _Sent,
+	     typename _Tp = iter_value_t<_Out>>
+      requires output_iterator<_Out, const _Tp&>
+#else
     template<typename _Tp,
 	     output_iterator<const _Tp&> _Out, sentinel_for<_Out> _Sent>
+#endif
       constexpr _Out
       operator()(_Out __first, _Sent __last, const _Tp& __value) const
       {
@@ -608,7 +623,12 @@  namespace ranges
 	  }
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<typename _Range, typename _Tp = range_value_t<_Range>>
+      requires output_range<_Range, const _Tp&>
+#else
     template<typename _Tp, output_range<const _Tp&> _Range>
+#endif
       constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, const _Tp& __value) const
       {
diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h
index e6d96073e87..062f272152e 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -36,6 +36,9 @@ 
 # include <bits/invoke.h>
 # include <bits/cpp_type_traits.h> // __can_use_memchr_for_find
 
+#define __glibcxx_want_default_template_type_for_algorithm_values
+#include <bits/version.h>
+
 #ifdef __glibcxx_ranges
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -487,8 +490,13 @@  namespace ranges
 {
   struct __find_fn
   {
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+	     typename _Proj = identity, typename _Tp = projected_value_t<_Iter, _Proj>>
+#else
     template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
 	     typename _Proj = identity>
+#endif
       requires indirect_binary_predicate<ranges::equal_to,
 					 projected<_Iter, _Proj>, const _Tp*>
       constexpr _Iter
@@ -521,7 +529,12 @@  namespace ranges
 	return __first;
       }
 
+#if __glibcxx_default_template_type_for_algorithm_values
+    template<input_range _Range, typename _Proj = identity,
+	     typename _Tp = projected_value_t<iterator_t<_Range>, _Proj>>
+#else
     template<input_range _Range, typename _Tp, typename _Proj = identity>
+#endif
       requires indirect_binary_predicate<ranges::equal_to,
 					 projected<iterator_t<_Range>, _Proj>,
 					 const _Tp*>
diff --git a/libstdc++-v3/include/bits/stl_algorithm_default.h b/libstdc++-v3/include/bits/stl_algorithm_default.h
new file mode 100644
index 00000000000..09e7be1b335
--- /dev/null
+++ b/libstdc++-v3/include/bits/stl_algorithm_default.h
@@ -0,0 +1,45 @@ 
+// Helpers for STL algorithms' default template argument  -*- C++ -*-
+
+// Copyright (C) 2007-2024 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/stl_algorithm_default.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{algorithm}
+ */
+
+#ifndef _GLIBCXX_STL_ALGORITHM_DEFAULT_H
+#define _GLIBCXX_STL_ALGORITHM_DEFAULT_H 1
+
+#include <bits/stl_iterator_base_types.h>
+
+#define __glibcxx_want_default_template_type_for_algorithm_values
+#include <bits/version.h>
+
+#if __glibcxx_default_template_type_for_algorithm_values // C++ >= 26
+#define _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_Iterator) \
+    = typename iterator_traits<_Iterator>::value_type
+#else
+#define _GLIBCXX26_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_It)
+#endif
+
+#endif
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 47335bfa6dd..1979751e7ba 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1828,6 +1828,14 @@  ftms = {
   };
 };
 
+ftms = {
+  name = default_template_type_for_algorithm_values;
+  values = {
+    v = 202403;
+    cxxmin = 26;
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index defe54ac1f2..497727e995c 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2038,4 +2038,14 @@ 
 #endif /* !defined(__cpp_lib_is_virtual_base_of) && defined(__glibcxx_want_is_virtual_base_of) */
 #undef __glibcxx_want_is_virtual_base_of
 
+#if !defined(__cpp_lib_default_template_type_for_algorithm_values)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_default_template_type_for_algorithm_values 202403L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_default_template_type_for_algorithm_values)
+#   define __cpp_lib_default_template_type_for_algorithm_values 202403L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_default_template_type_for_algorithm_values) && defined(__glibcxx_want_default_template_type_for_algorithm_values) */
+#undef __glibcxx_want_default_template_type_for_algorithm_values
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/pstl/glue_algorithm_defs.h b/libstdc++-v3/include/pstl/glue_algorithm_defs.h
index cef78e22e31..8c07c25cd92 100644
--- a/libstdc++-v3/include/pstl/glue_algorithm_defs.h
+++ b/libstdc++-v3/include/pstl/glue_algorithm_defs.h
@@ -11,6 +11,7 @@ 
 #define _PSTL_GLUE_ALGORITHM_DEFS_H
 
 #include <bits/stl_pair.h>
+#include <bits/stl_algorithm_default.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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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_DEFAULT_TEMPLATE_TYPE_FOR_ALGORITHM_VALUE(_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..359617b8672 100644
--- a/libstdc++-v3/include/std/algorithm
+++ b/libstdc++-v3/include/std/algorithm
@@ -65,6 +65,7 @@ 
 
 #define __glibcxx_want_clamp
 #define __glibcxx_want_constexpr_algorithms
+#define __glibcxx_want_default_template_type_for_algorithm_values
 #define __glibcxx_want_freestanding_algorithm
 #define __glibcxx_want_parallel_algorithm
 #define __glibcxx_want_ranges
diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque
index 0bf8309c19a..05acb8a0d54 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_default_template_type_for_algorithm_values
 #define __glibcxx_want_erase_if
 #define __glibcxx_want_nonmember_container_access
 #include <bits/version.h>
@@ -115,7 +116,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return 0;
     }
 
-  template<typename _Tp, typename _Alloc, typename _Up>
+  template<typename _Tp, typename _Alloc, typename _Up
+#if __glibcxx_default_template_type_for_algorithm_values // C++ >= 26
+	   = _Tp
+#endif
+  >
     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 5ac74360808..4419d0e5aec 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_default_template_type_for_algorithm_values
 #define __glibcxx_want_erase_if
 #define __glibcxx_want_incomplete_container_elements
 #define __glibcxx_want_list_remove_return_type
@@ -74,7 +75,11 @@  _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
+#if __glibcxx_default_template_type_for_algorithm_values // C++ >= 26
+	   = _Tp
+#endif
+  >
     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 fce4e3d925b..9b5e9957786 100644
--- a/libstdc++-v3/include/std/list
+++ b/libstdc++-v3/include/std/list
@@ -69,6 +69,7 @@ 
 # include <debug/list>
 #endif
 
+#define __glibcxx_want_default_template_type_for_algorithm_values
 #define __glibcxx_want_erase_if
 #define __glibcxx_want_incomplete_container_elements
 #define __glibcxx_want_list_remove_return_type
@@ -98,7 +99,11 @@  _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
+#if __glibcxx_default_template_type_for_algorithm_values // C++ >= 26
+	   = _Tp
+#endif
+  >
     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 b7c7aa36ddc..8dca469dd2c 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_default_template_type_for_algorithm_values
 #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 55144409cca..54c751038cd 100644
--- a/libstdc++-v3/include/std/string
+++ b/libstdc++-v3/include/std/string
@@ -56,6 +56,7 @@ 
 
 #define __glibcxx_want_constexpr_char_traits
 #define __glibcxx_want_constexpr_string
+#define __glibcxx_want_default_template_type_for_algorithm_values
 #define __glibcxx_want_erase_if
 #define __glibcxx_want_nonmember_container_access
 #define __glibcxx_want_string_resize_and_overwrite
@@ -104,7 +105,11 @@  _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
+#if __glibcxx_default_template_type_for_algorithm_values // C++ >= 26
+	   = _CharT
+#endif
+  >
     _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 a1f7ef86824..e5262e82b89 100644
--- a/libstdc++-v3/include/std/vector
+++ b/libstdc++-v3/include/std/vector
@@ -77,6 +77,7 @@ 
 #endif
 
 #define __glibcxx_want_constexpr_vector
+#define __glibcxx_want_default_template_type_for_algorithm_values
 #define __glibcxx_want_erase_if
 #define __glibcxx_want_incomplete_container_elements
 #define __glibcxx_want_nonmember_container_access
@@ -128,7 +129,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return 0;
     }
 
-  template<typename _Tp, typename _Alloc, typename _Up>
+  template<typename _Tp, typename _Alloc, typename _Up
+#if __glibcxx_default_template_type_for_algorithm_values // C++ >= 26
+	   = _Tp
+#endif
+  >
     _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..070e0deea4c
--- /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_default_template_type_for_algorithm_values)
+#error "Feature test macro for default template type for algorithms' values is missing"
+#elif __cpp_lib_default_template_type_for_algorithm_values < 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..6086d441168
--- /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_default_template_type_for_algorithm_values)
+#error "Feature test macro for default template type for algorithms' values is missing"
+#elif __cpp_lib_default_template_type_for_algorithm_values < 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);
+}
-- 
2.34.1