[gcc r17-2705] libstdc++: Implement LWG 4074 changes to join_with_view's constraints

Patrick Palka ppalka@gcc.gnu.org
Sat Jul 25 20:13:25 GMT 2026


https://gcc.gnu.org/g:368574dc98d3ad15fd099080965826e2afda963c

commit r17-2705-g368574dc98d3ad15fd099080965826e2afda963c
Author: Patrick Palka <ppalka@redhat.com>
Date:   Sat Jul 25 16:12:16 2026 -0400

    libstdc++: Implement LWG 4074 changes to join_with_view's constraints
    
    libstdc++-v3/ChangeLog:
    
            * include/std/ranges (__detail::__compatible_joinable_ranges):
            Remove.
            (__detail::__concat_reference_t): Move definition up.
            (__detail::__concat_value_t): Likewise.
            (__detail::__concat_rvalue_reference_t): Likewise.
            (__detail::__concat_indirectly_readable_impl): Likewise.
            (__detail::__concat_indirectly_readable): Likewise.
            (__detail::__concatable): Likewise.
            (join_with_view): Use __concatable instead of
            __compatible_joinable_ranges in constraints as per LWG 4074.
            (join_with_view::begin): Add __concatable constraint as per
            LWG 4074.
            (join_with_view::end): Likewise.
            (join_with_view::_Iterator): Adjust out-of-line declaration.
            (join_with_view::_Sentinel): Likewise.
    
    Reviewed-by: Jonathan Wakely <jwakely@redhat.com>

Diff:
---
 libstdc++-v3/include/std/ranges | 88 ++++++++++++++++++++---------------------
 1 file changed, 42 insertions(+), 46 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 3e0df8d083c0..07e26542f9e2 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -7363,22 +7363,51 @@ namespace views::__adaptor
 #ifdef __cpp_lib_ranges_join_with // C++ >= 23
   namespace __detail
   {
-    template<typename _Range, typename _Pattern>
-      concept __compatible_joinable_ranges
-	= common_with<range_value_t<_Range>, range_value_t<_Pattern>>
-	  && common_reference_with<range_reference_t<_Range>,
-				   range_reference_t<_Pattern>>
-	  && common_reference_with<range_rvalue_reference_t<_Range>,
-				   range_rvalue_reference_t<_Pattern>>;
-
     template<typename _Range>
       concept __bidirectional_common = bidirectional_range<_Range> && common_range<_Range>;
+
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 4074. compatible-joinable-ranges is underconstrained
+    template<typename... _Rs>
+      using __concat_reference_t = common_reference_t<range_reference_t<_Rs>...>;
+
+    template<typename... _Rs>
+      using __concat_value_t = common_type_t<range_value_t<_Rs>...>;
+
+    template<typename... _Rs>
+      using __concat_rvalue_reference_t
+	= common_reference_t<range_rvalue_reference_t<_Rs>...>;
+
+    template<typename _Ref, typename _RRef, typename _It>
+      concept __concat_indirectly_readable_impl = requires(const _It __it) {
+	{ *__it } -> convertible_to<_Ref>;
+	{ ranges::iter_move(__it) } -> convertible_to<_RRef>;
+      };
+
+    template<typename... _Rs>
+      concept __concat_indirectly_readable
+	= common_reference_with<__concat_reference_t<_Rs...>&&, __concat_value_t<_Rs...>&>
+	  && common_reference_with<__concat_reference_t<_Rs...>&&,
+				   __concat_rvalue_reference_t<_Rs...>&&>
+	  && common_reference_with<__concat_rvalue_reference_t<_Rs...>&&,
+				   __concat_value_t<_Rs...> const&>
+	  && (__concat_indirectly_readable_impl<__concat_reference_t<_Rs...>,
+						__concat_rvalue_reference_t<_Rs...>,
+						iterator_t<_Rs>>
+	      && ...);
+
+    template<typename... _Rs>
+      concept __concatable = requires {
+	typename __concat_reference_t<_Rs...>;
+	typename __concat_value_t<_Rs...>;
+	typename __concat_rvalue_reference_t<_Rs...>;
+      } && __concat_indirectly_readable<_Rs...>;
   }
 
   template<input_range _Vp, forward_range _Pattern>
     requires view<_Vp> && view<_Pattern>
       && input_range<range_reference_t<_Vp>>
-      && __detail::__compatible_joinable_ranges<range_reference_t<_Vp>, _Pattern>
+      && __detail::__concatable<range_reference_t<_Vp>, _Pattern>
   class join_with_view : public view_interface<join_with_view<_Vp, _Pattern>>
   {
     using _InnerRange = range_reference_t<_Vp>;
@@ -7495,6 +7524,7 @@ namespace views::__adaptor
 	&& forward_range<const _Pattern>
 	&& is_reference_v<range_reference_t<const _Vp>>
 	&& input_range<range_reference_t<const _Vp>>
+	&& __detail::__concatable<range_reference_t<const _Vp>, const _Pattern>
     { return _Iterator<true>{*this, ranges::begin(_M_base)}; }
 
     constexpr auto
@@ -7516,6 +7546,7 @@ namespace views::__adaptor
 	&& forward_range<const _Pattern>
 	&& is_reference_v<range_reference_t<const _Vp>>
 	&& input_range<range_reference_t<const _Vp>>
+	&& __detail::__concatable<range_reference_t<const _Vp>, const _Pattern>
     {
       using _InnerConstRange = range_reference_t<const _Vp>;
       if constexpr (forward_range<_InnerConstRange>
@@ -7539,7 +7570,7 @@ namespace views::__adaptor
   template<input_range _Vp, forward_range _Pattern>
     requires view<_Vp> && view<_Pattern>
       && input_range<range_reference_t<_Vp>>
-      && __detail::__compatible_joinable_ranges<range_reference_t<_Vp>, _Pattern>
+      && __detail::__concatable<range_reference_t<_Vp>, _Pattern>
   template<bool _Const>
   class join_with_view<_Vp, _Pattern>::_Iterator : public __iter_cat<_Const>
   {
@@ -7828,7 +7859,7 @@ namespace views::__adaptor
   template<input_range _Vp, forward_range _Pattern>
     requires view<_Vp> && view<_Pattern>
       && input_range<range_reference_t<_Vp>>
-      && __detail::__compatible_joinable_ranges<range_reference_t<_Vp>, _Pattern>
+      && __detail::__concatable<range_reference_t<_Vp>, _Pattern>
   template<bool _Const>
   class join_with_view<_Vp, _Pattern>::_Sentinel
   {
@@ -9810,41 +9841,6 @@ namespace ranges
 {
   namespace __detail
   {
-    template<typename... _Rs>
-      using __concat_reference_t = common_reference_t<range_reference_t<_Rs>...>;
-
-    template<typename... _Rs>
-      using __concat_value_t = common_type_t<range_value_t<_Rs>...>;
-
-    template<typename... _Rs>
-      using __concat_rvalue_reference_t
-	= common_reference_t<range_rvalue_reference_t<_Rs>...>;
-
-    template<typename _Ref, typename _RRef, typename _It>
-      concept __concat_indirectly_readable_impl = requires(const _It __it) {
-	{ *__it } -> convertible_to<_Ref>;
-	{ ranges::iter_move(__it) } -> convertible_to<_RRef>;
-      };
-
-    template<typename... _Rs>
-      concept __concat_indirectly_readable
-	= common_reference_with<__concat_reference_t<_Rs...>&&, __concat_value_t<_Rs...>&>
-	  && common_reference_with<__concat_reference_t<_Rs...>&&,
-				   __concat_rvalue_reference_t<_Rs...>&&>
-	  && common_reference_with<__concat_rvalue_reference_t<_Rs...>&&,
-				   __concat_value_t<_Rs...> const&>
-	  && (__concat_indirectly_readable_impl<__concat_reference_t<_Rs...>,
-						__concat_rvalue_reference_t<_Rs...>,
-						iterator_t<_Rs>>
-	      && ...);
-
-    template<typename... _Rs>
-      concept __concatable = requires {
-	typename __concat_reference_t<_Rs...>;
-	typename __concat_value_t<_Rs...>;
-	typename __concat_rvalue_reference_t<_Rs...>;
-      } && __concat_indirectly_readable<_Rs...>;
-
     template<bool _Const, typename _Range, typename... _Rs>
       struct __all_but_last_common
       {


More information about the Libstdc++-cvs mailing list