diff --git a/concat.md b/concat.md index 7afa32a..e70ca07 100644 --- a/concat.md +++ b/concat.md @@ -13,6 +13,12 @@ toc: true # Revision History +## R4 + - Added additional constraint to `views::concat` to disable any combination of + range arguments that has a prvalue reference type, and another with a that of a + reference to that same type. Also added `views::concat_magic` to neglect this + additional constraint. + ## R3 - Redesigned `iter_swap` @@ -463,12 +469,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_magic = @_unspecified_@; } } @@ -524,13 +531,21 @@ 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 +[2]{.pnum} The names `views::concat` and `views::concat_magic` 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_magic(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 +576,9 @@ namespace std::ranges { concept @*concat-indirectly-readable*@ = @*see below*@; // exposition only template + concept @*concat-no-magic*@ = @*see below*@; // exposition only + + template concept @_concatable_@ = @*see below*@; // exposition only template @@ -574,10 +592,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 +621,7 @@ namespace std::ranges { }; template - concat_view(R&&...) -> concat_view...>; + concat_view(R&&...) -> concat_view...>; } ``` @@ -640,8 +658,29 @@ concept @*concat-indirectly-readable*@ = // exposition only ::: + +```cpp +template +concept @*concat-no-magic*@ = @*see below*@; // exposition only +``` + +:::bq + +[2]{.pnum} The exposition-only `@*concat-no-magic*@` concept is equivalent to: + ```cpp template +concept @*concat-no-magic*@ = // 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 +690,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*@ + && (allow_magic || @*concat-no-magic*@); ``` ::: @@ -709,7 +749,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 +814,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..ee2595a 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...>; +template +concept concat_no_magic = // modelled only if concat reference_t is a prvalue T + // and at least one of the range's refernce_t is a T + // reference + 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 + && (allow_magic || concat_no_magic) +; // 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_magic_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_magic_fn concat_magic; } // namespace views } // namespace std::ranges