diff --git a/concat.md b/concat.md index 7afa32a..36693d5 100644 --- a/concat.md +++ b/concat.md @@ -13,6 +13,9 @@ toc: true # Revision History +## R4 + - Added `views::concat_expert`. + ## R3 - Redesigned `iter_swap` @@ -463,12 +466,13 @@ namespace std::ranges { // [...] // [range.concat], concat view - template + template requires @*see below*@ class concat_view; namespace views { inline constexpr @_unspecified_@ concat = @_unspecified_@; + inline constexpr @_unspecified_@ concat_expert = @_unspecified_@; } } @@ -524,13 +528,22 @@ Add the following subclause to [range.adaptors]{.sref}. [1]{.pnum} `concat_view` presents a `view` that concatenates all the underlying ranges. -[2]{.pnum} The name `views::concat` denotes a customization point object -([customization.point.object]{.sref}). Given a pack of subexpressions `Es...`, -the expression `views::concat(Es...)` is expression-equivalent to +[2]{.pnum} The names `views::concat` and `views::concat_expert` denote two +customization point objects ([customization.point.object]{.sref}). Given a pack +of subexpressions `Es...`, the expression `views::concat(Es...)` is +expression-equivalent to - [2.1]{.pnum} `views::all(Es...)` if `Es` is a pack with only one element and `views::all(Es...)` is a well formed expression, -- [2.2]{.pnum} otherwise, `concat_view(Es...)` +- [2.2]{.pnum} otherwise, `concat_view(Es...)`, which is deduced to be the type + `concat_view...>`. + +And, the expression `views::concat_expert(Es...)` is expression-equivalent to + +- [2.3]{.pnum} `views::all(Es...)` if `Es` is a pack with only one element + and `views::all(Es...)` is a well formed expression, +- [2.4]{.pnum} otherwise, `concat_view...>(Es...)`. + \[*Example:* ```cpp @@ -561,6 +574,9 @@ namespace std::ranges { concept @*concat-indirectly-readable*@ = @*see below*@; // exposition only template + concept @*concat-require-expert*@ = @*see below*@; // exposition only + + template concept @_concatable_@ = @*see below*@; // exposition only template @@ -574,10 +590,10 @@ namespace std::ranges { template concept @_concat-is-bidirectional_@ = @*see below*@; // exposition only - template + template requires (view && ...) && (sizeof...(Views) > 0) && - @_concatable_@ - class concat_view : public view_interface> { + @_concatable_@ + class concat_view : public view_interface> { tuple @*views_*@; // exposition only template @@ -603,7 +619,7 @@ namespace std::ranges { }; template - concat_view(R&&...) -> concat_view...>; + concat_view(R&&...) -> concat_view...>; } ``` @@ -640,8 +656,29 @@ concept @*concat-indirectly-readable*@ = // exposition only ::: + +```cpp +template +concept @*concat-require-expert*@ = @*see below*@; // exposition only +``` + +:::bq + +[2]{.pnum} The exposition-only `@*concat-require-expert*@` concept is equivalent to: + ```cpp template +concept @*concat-require-expert*@ = // exposition only + is_reference_v<@*concat-reference-t*@> || + ((!is_reference_v> || + !same_as>, @*concat-reference-t*@>) + && ...); +``` + +::: + +```cpp +template concept @_concatable_@ = @*see below*@; // exposition only ``` @@ -651,12 +688,13 @@ concept @_concatable_@ = @*see below*@; // exposition only concept is equivalent to: ```cpp -template +template concept @_concatable_@ = requires { // exposition only typename @*concat-reference-t*@; typename @*concat-value-t*@; typename @*concat-rvalue-reference-t*@; -} && @*concat-indirectly-readable*@; +} && @*concat-indirectly-readable*@ + && (expert_mode || @*concat-require-expert*@); ``` ::: @@ -709,7 +747,7 @@ constexpr explicit concat_view(Views... views); ```cpp constexpr @_iterator_@ begin() requires(!(@_simple-view_@ && ...)); constexpr @_iterator_@ begin() const - requires((range && ...) && @_concatable_@); + requires((range && ...) && @_concatable_@); ``` :::bq @@ -774,11 +812,11 @@ return apply( ```cpp namespace std::ranges{ - template + template requires (view && ...) && (sizeof...(Views) > 0) && - @_concatable_@ + @_concatable_@ template - class concat_view::@_iterator_@ { + class concat_view::@_iterator_@ { public: using iterator_category = @*see below*@; // not always present. diff --git a/impl/concat/concat.hpp b/impl/concat/concat.hpp index a21c71f..3f72120 100644 --- a/impl/concat/concat.hpp +++ b/impl/concat/concat.hpp @@ -37,6 +37,16 @@ using concat_rvalue_reference_t = template using concat_value_t = common_type_t...>; +// modelled only if concat reference_t is a prvalue T and at least one of the +// argument ranges' reference_t is a T reference +template +concept concat_require_expert = + is_reference_v> || + (is_reference_v>&&...) && + (!same_as>, + concat_reference_t> && + ...); + // clang-format off template concept concat_indirectly_readable_impl = requires (const It it){ @@ -55,12 +65,14 @@ concept concat_indirectly_readable = } // namespace not_to_spec // clang-format off -template +template concept concatable = requires { typename concat_reference_t; typename concat_value_t; typename concat_rvalue_reference_t; -} && concat_indirectly_readable; +} && concat_indirectly_readable + && (expert_mode || concat_require_expert) +; // clang-format on static_assert(true); // clang-format badness @@ -246,9 +258,9 @@ using iter_cat_base_t = decltype(iter_cat_base_sel()); // clang-format off // [TODO] constrain less and allow just a `view`? (i.e. including output_range in the mix - need an example) -template - requires (view&&...) && (sizeof...(Views) > 0) && xo::concatable -class concat_view : public view_interface> { +template + requires (view&&...) && (sizeof...(Views) > 0) && xo::concatable +class concat_view : public view_interface> { // clang-format on tuple views_; // exposition only @@ -636,7 +648,7 @@ class concat_view : public view_interface> { constexpr iterator begin() const requires((range && ...) && - xo::concatable) // + xo::concatable) // { iterator it{this, in_place_index<0u>, ranges::begin(get<0>(views_))}; it.template satisfy<0>(); @@ -685,7 +697,7 @@ class concat_view : public view_interface> { }; template -concat_view(R&&...) -> concat_view...>; +concat_view(R&&...) -> concat_view...>; // cpo: @@ -702,7 +714,7 @@ class concat_fn { } template - requires(sizeof...(V) > 1) && ranges::xo::concatable...> && + requires(sizeof...(V) > 1) && ranges::xo::concatable...> && (viewable_range && ...) // constexpr auto operator()(V&&... v) @@ -710,9 +722,22 @@ class concat_fn { return concat_view{static_cast(v)...}; } }; + +class concat_expert_fn : concat_fn { + public: + template + requires(sizeof...(V) > 1) && ranges::xo::concatable...> && + (viewable_range && ...) // + constexpr auto + operator()(V&&... v) + const { // noexcept(noexcept(concat_view{static_cast(v)...})) { + return concat_view...>{static_cast(v)...}; + } +}; } // namespace xo inline constexpr xo::concat_fn concat; +inline constexpr xo::concat_expert_fn concat_expert; } // namespace views } // namespace std::ranges