On Mon, 13 Jul 2026 at 16:24, Patrick Palka <[email protected]> wrote:
>
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk/16? I tried
> for a bit to contrive a testcase for this change but concluded it's not
> worth it. What's more important is that this change doesn't break
> idiomatic uses of join_with_view which should already be covered by
> existing tests.
OK for trunk and 16
>
> -- >8 --
>
> 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.
> ---
> libstdc++-v3/include/std/ranges | 86 +++++++++++++++------------------
> 1 file changed, 40 insertions(+), 46 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index 39a50b03e457..87c443c729b9 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -7363,22 +7363,49 @@ 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>;
> +
> + 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 +7522,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 +7544,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 +7568,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 +7857,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
> {
> @@ -9804,41 +9833,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
> {
> --
> 2.55.0.122.gf85a7e6620
>