diff --git a/doc/rvariant.adoc b/doc/rvariant.adoc index b723074..63b2c1c 100644 --- a/doc/rvariant.adoc +++ b/doc/rvariant.adoc @@ -22,9 +22,9 @@ Yaito Kakeyama; Nana Sakisaka :exposition-only: pass:quotes[[.exposition-only]#exposition only#] :bad-variant-access: pass:quotes,macros[https://eel.is/c++draft/variant.bad.access[`std::bad_variant_access`]] -:unwrap_recursive_t: <> +:unwrap_recursive_type: <> +:unwrap_recursive: pass:quotes[xref:#rvariant.recursive.helper[unwrap_recursive]] :recursive_wrapper: pass:macros[xref:#rvariant.recursive[recursive_wrapper]] -:UNWRAP_RECURSIVE: pass:quotes[_xref:#rvariant.recursive.helper[UNWRAP_RECURSIVE]_] :subset_of: <> :equivalent_to: <> @@ -51,7 +51,7 @@ expr.visit(temp_ns::overloaded{ === Supported Environments * GCC 14 * Clang 21-22 (lib{cxx}) -* MSVC (2022) +* MSVC 2022 and 2026 * {cpp}23 and {cpp}26 @@ -380,9 +380,8 @@ template /* constexpr */ std::size_t hash_value(recursive_wrapper const&); // <>, pass:quotes[`recursive_wrapper`] helper classes -template struct unwrap_recursive; -template struct unwrap_recursive>; -template using unwrap_recursive_t = typename unwrap_recursive::type; +template using unwrap_recursive_type = {see-below}; +template constexpr auto&& unwrap_recursive(T&& o) noexcept; // <>, pack manipulation and deduping template class TT, class A, class B> @@ -516,7 +515,7 @@ rvariant< ---- -- -* Let `VT~_i_~` denote `{recursive_wrapper}` (for any type `A`) if such a specialization occurs anywhere in `Ts\...`; otherwise, let `VT~_i_~` denote `T~_i_~`. Let `U~_j_~` denote the _j_^th^ type of the template parameter pack having the name `Us` on each flexibility-related functions. [.underline]#The _corresponding alternative_ for `rvariant` is the first type for which `std::is_same_v<{unwrap_recursive_t}, {unwrap_recursive_t}>` is `true`#. +* Let `VT~_i_~` denote `{recursive_wrapper}` (for any type `A`) if such a specialization occurs anywhere in `Ts\...`; otherwise, let `VT~_i_~` denote `T~_i_~`. Let `U~_j_~` denote the _j_^th^ type of the template parameter pack having the name `Us` on each flexibility-related functions. [.underline]#The _corresponding alternative_ for `rvariant` is the first type for which `std::is_same_v<{unwrap_recursive_type}, {unwrap_recursive_type}>` is `true`#. [[rvariant.ctor]] @@ -562,7 +561,7 @@ include::_std-variant-proxy.adoc[] * [.candidate]#4)# _Generic constructor_. Equivalent to the `std::variant` counterpart, ^https://eel.is/c++draft/variant.ctor[[spec\]]^ except: + -*_Postconditions:_* `holds_alternative[.underline]##<{unwrap_recursive_t}>##(*this)` is `true`. +*_Postconditions:_* `holds_alternative[.underline]##<{unwrap_recursive_type}>##(*this)` is `true`. * [.candidate]#5)# *_Mandates:_* [.underline]#`T` is not a specialization of `{recursive_wrapper}`#. + @@ -572,7 +571,7 @@ include::_std-variant-proxy.adoc[] + -- [none] -** -- There is exactly one occurrence of `T` in [.underline]#`{unwrap_recursive_t}\...`# and +** -- There is exactly one occurrence of `T` in [.underline]#`{unwrap_recursive_type}\...`# and ** -- `std::is_constructible_v<[.underline]##VT##, Args\...>` is `true`. -- + @@ -592,7 +591,7 @@ include::_std-variant-proxy.adoc[] + -- [none] -** -- There is exactly one occurrence of `T` in [.underline]#`{unwrap_recursive_t}\...`# and +** -- There is exactly one occurrence of `T` in [.underline]#`{unwrap_recursive_type}\...`# and ** -- `std::is_constructible_v<[.underline]##VT##, std::initializer_list&, Args\...>` is `true`. -- + @@ -617,7 +616,7 @@ include::_std-variant-proxy.adoc[] [none] ** -- `std::is_same_v, rvariant>` is `false`, and ** -- [.underline]#`{subset_of}, rvariant>` is `true`, and# -** -- [.underline]#`std::disjunction_v, {unwrap_recursive_t}>\...>` is `false`, and# +** -- [.underline]#`std::disjunction_v, {unwrap_recursive_type}>\...>` is `false`, and# ** -- [.underline]#`std::is_constructible_v` is `true` for all _j_.# -- + @@ -641,7 +640,7 @@ include::_std-variant-proxy.adoc[] [none] ** -- `std::is_same_v, rvariant>` is `false`, and ** -- `{subset_of}, rvariant>` is `true`, and -** -- `std::disjunction_v, {unwrap_recursive_t}>\...>` is `false`, and +** -- `std::disjunction_v, {unwrap_recursive_type}>\...>` is `false`, and ** -- `std::is_constructible_v` is `true` for all _j_. -- + @@ -699,7 +698,7 @@ include::_std-variant-proxy.adoc[] * [.candidate]#3)# _Generic assignment operator_. Equivalent to the `std::variant` counterpart, ^https://eel.is/c++draft/variant.assign[[spec\]]^ except: + -*_Postconditions:_* `holds_alternative[.underline]##<{unwrap_recursive_t}>##(*this)` is `true`, with `T~_j_~` selected by the imaginary function overload resolution described above. +*_Postconditions:_* `holds_alternative[.underline]##<{unwrap_recursive_type}>##(*this)` is `true`, with `T~_j_~` selected by the imaginary function overload resolution described above. * [.candidate]#4)# _Flexible copy assignment operator_. + @@ -711,7 +710,7 @@ include::_std-variant-proxy.adoc[] [none] ** -- `std::is_same_v, rvariant>` is `false`, and ** -- [.underline]#`{subset_of}, rvariant>` is `true`, and# -** -- [.underline]#`std::disjunction_v, {unwrap_recursive_t}>\...>` is `false`, and# +** -- [.underline]#`std::disjunction_v, {unwrap_recursive_type}>\...>` is `false`, and# ** -- [.underline]#`std::is_constructible_v && std::is_assignable_v` is `true` for all _j_.# -- + @@ -722,7 +721,7 @@ include::_std-variant-proxy.adoc[] ** -- If neither `*this` nor `rhs` holds a value, there is no effect. ** -- Otherwise, if `*this` holds a value but `rhs` does not, destroys the value contained in `*this` and sets `*this` to not hold a value. ** -- Otherwise, if `rhs` holds a value but `*this` does not, initializes `rvariant` to hold [.underline]#`VT~_i_~` (with _i_ being the index of the alternative corresponding to that of `rhs`)# and direct-initializes the contained value with [.underline]#`_GET_<__j__>(rhs)`.# -** -- Otherwise, if [.underline]#`std::is_same_v<{unwrap_recursive_t}, {unwrap_recursive_t}>` is `true`#, assigns [.underline]#`_GET_<__j__>(rhs)`# to the value contained in `*this`. [.underline]#(_Note:_ the left hand side is `T~_i_~`, _not_ `VT~_i_~`. This ensures that the existing storage is reused even for `rvariant` with duplicate corresponding alternatives; i.e., `index()` is unchanged.)# +** -- Otherwise, if [.underline]#`std::is_same_v<{unwrap_recursive_type}, {unwrap_recursive_type}>` is `true`#, assigns [.underline]#`_GET_<__j__>(rhs)`# to the value contained in `*this`. [.underline]#(_Note:_ the left hand side is `T~_i_~`, _not_ `VT~_i_~`. This ensures that the existing storage is reused even for `rvariant` with duplicate corresponding alternatives; i.e., `index()` is unchanged.)# ** -- Otherwise, if either `std::is_nothrow_constructible_v` is `true` or `std::is_nothrow_move_constructible_v` is `false`, equivalent to `emplace[.underline]####(_GET_<__j__>(rhs))`. ** -- Otherwise, equivalent to `emplace([.underline]##VT~_i_~##(_GET_<__j__>(rhs)))`. -- @@ -743,7 +742,7 @@ include::_std-variant-proxy.adoc[] [none] ** -- [.underline]#`std::is_same_v, rvariant>` is `false`,# ** -- [.underline]#`{subset_of}, rvariant>` is `true`, and# -** -- [.underline]#`std::disjunction_v, {unwrap_recursive_t}>\...>` is `false`, and# +** -- [.underline]#`std::disjunction_v, {unwrap_recursive_type}>\...>` is `false`, and# ** -- [.underline]#`std::is_constructible_v && std::is_assignable_v` is `true` for all _j_.# -- + @@ -754,7 +753,7 @@ include::_std-variant-proxy.adoc[] ** -- If neither `*this` nor `rhs` holds a value, there is no effect. ** -- Otherwise, if `*this` holds a value but `rhs` does not, destroys the value contained in `*this` and sets `*this` to not hold a value. ** -- Otherwise, if `rhs` holds a value but `*this` does not, initializes `rvariant` to hold [.underline]#`VT~_i_~` (with _i_ being the index of the alternative corresponding to that of `rhs`)# and direct-initializes the contained value with [.underline]#`_GET_<__j__>(std::move(rhs))`.# -** -- Otherwise, if [.underline]#`std::is_same_v<{unwrap_recursive_t}, {unwrap_recursive_t}>` is `true`#, assigns [.underline]#`_GET_<__j__>(std::move(rhs))`# to the value contained in `*this`. [.underline]#(_Note:_ the left hand side is `T~_i_~`, _not_ `VT~_i_~`. This ensures that the existing storage is reused even for `rvariant` with duplicate corresponding alternatives; i.e., `index()` is unchanged.)# +** -- Otherwise, if [.underline]#`std::is_same_v<{unwrap_recursive_type}, {unwrap_recursive_type}>` is `true`#, assigns [.underline]#`_GET_<__j__>(std::move(rhs))`# to the value contained in `*this`. [.underline]#(_Note:_ the left hand side is `T~_i_~`, _not_ `VT~_i_~`. This ensures that the existing storage is reused even for `rvariant` with duplicate corresponding alternatives; i.e., `index()` is unchanged.)# ** -- Otherwise, equivalent to `emplace[.underline]####(_GET_<__j__>(std::move(rhs)))`. -- + @@ -790,31 +789,31 @@ constexpr variant_alternative_t>& + *_Mandates:_* [.underline]#`T` is not a specialization of `{recursive_wrapper}`.# + -*_Constraints:_* `std::is_constructible_v<[.underline]##VT##, Args\...>` is `true`, and `T` occurs exactly once in [.underline]#`{unwrap_recursive_t}`#. +*_Constraints:_* `std::is_constructible_v<[.underline]##VT##, Args\...>` is `true`, and `T` occurs exactly once in [.underline]#`{unwrap_recursive_type}`#. + *_Effects:_* Equivalent to: + pass:quotes[  ]`return emplace<__I__>(std::forward(args)\...);` + -where `_I_` is the zero-based index of `T` in [.underline]#`{unwrap_recursive_t}`#. +where `_I_` is the zero-based index of `T` in [.underline]#`{unwrap_recursive_type}`#. * [.candidate]#2)# [.underline]#Let `VT` denote `{recursive_wrapper}` (for any type `A`) if such a specialization occurs anywhere in `Ts\...`; otherwise, let `VT` denote `T`.# + *_Mandates:_* [.underline]#`T` is not a specialization of `{recursive_wrapper}`.# + -*_Constraints:_* `std::is_constructible_v<[.underline]##VT##, std::initializer_list&, Args\...>` is `true`, and `T` occurs exactly once in [.underline]#`{unwrap_recursive_t}`#. +*_Constraints:_* `std::is_constructible_v<[.underline]##VT##, std::initializer_list&, Args\...>` is `true`, and `T` occurs exactly once in [.underline]#`{unwrap_recursive_type}`#. + *_Effects:_* Equivalent to: + pass:quotes[  ]`return emplace<__I__>(il, std::forward(args)\...);` + -where `_I_` is the zero-based index of `T` in [.underline]#`{unwrap_recursive_t}`#. +where `_I_` is the zero-based index of `T` in [.underline]#`{unwrap_recursive_type}`#. * [.candidate]#3)# Equivalent to the `std::variant` counterpart, ^https://eel.is/c++draft/variant.mod[[spec\]]^ except: + -*_Returns:_* [.underline]#Let `o` denote# a reference to the new contained value. [.underline]#Returns `{UNWRAP_RECURSIVE}(o)`.# +*_Returns:_* [.underline]#Let `o` denote# a reference to the new contained value. [.underline]#Returns `{unwrap_recursive}(o)`.# + *_Remarks:_* [.underline]#If `T~_I_~` is a specialization of `{recursive_wrapper}`, this function is permitted to construct an intermediate variable `tmp` as if by passing `std::forward(args)\...` to ``T~_I_~``'s constructor. Then `rvariant` direct-non-list-initializes the contained value of `T~_I_~` with the argument `std::move(tmp)`. (_Note:_ This allows optimization where `rvariant` can be assumed to become never valueless on certain cases.)# * [.candidate]#4)# Equivalent to the `std::variant` counterpart, ^https://eel.is/c++draft/variant.mod[[spec\]]^ except: + -*_Returns:_* [.underline]#Let `o` denote# a reference to the new contained value. [.underline]#Returns `{UNWRAP_RECURSIVE}(o)`.# +*_Returns:_* [.underline]#Let `o` denote# a reference to the new contained value. [.underline]#Returns `{unwrap_recursive}(o)`.# + *_Remarks:_* [.underline]#If `T~_I_~` is a specialization of `{recursive_wrapper}`, this function is permitted to construct an intermediate variable `tmp` as if by passing `il, std::forward(args)\...` to ``T~_I_~``'s constructor. Then `rvariant` direct-non-list-initializes the contained value of `T~_I_~` with the argument `std::move(tmp)`. (_Note:_ This allows optimization where `rvariant` can be assumed to become never valueless on certain cases.)# @@ -930,7 +929,7 @@ struct variant_alternative>;pass:quotes[[.candidate\]#// 2#] * [.candidate]#1)# include::_std-variant-proxy.adoc[] -* [.candidate]#2)# The member typedef `type` denotes [.underline]#`{unwrap_recursive_t}`#. +* [.candidate]#2)# The member typedef `type` denotes [.underline]#`{unwrap_recursive_type}`#. + *_Mandates:_* `I < sizeof\...(Ts)`. @@ -967,7 +966,7 @@ concept equivalent_to = subset_of && subset_of; + [none] ** -- `T` is the same type as `U` or, -** -- `{unwrap_recursive_t}` is the same type as `U`. +** -- `{unwrap_recursive_type}` is the same type as `U`. [[rvariant.get]] @@ -984,9 +983,9 @@ constexpr bool holds_alternative(rvariant const& v) noexcept; ---- [.candidates] -* [.candidate]#{empty}# *_Mandates:_* The type `T` occurs exactly once in [.underline]#`{unwrap_recursive_t}`#. +* [.candidate]#{empty}# *_Mandates:_* The type `T` occurs exactly once in [.underline]#`{unwrap_recursive_type}`#. + -*_Returns:_* `true` if `v.index()` is equal to the zero-based index of `T` in [.underline]#`{unwrap_recursive_t}`#. +*_Returns:_* `true` if `v.index()` is equal to the zero-based index of `T` in [.underline]#`{unwrap_recursive_type}`#. + *_Remarks:_* [.underline]#This function is defined as deleted if `T` is a specialization of `{recursive_wrapper}`.# @@ -1011,7 +1010,7 @@ constexpr {see-below} const&& pass:quotes[_GET_](rvariant const&& v); // + *_Preconditions:_* `v.index()` is `I`. + -*_Returns:_* [.underline]#`o`, where `o` denotes a reference to the object stored in `v`, if the type of the expression's receiver is a specialization of `{recursive_wrapper}`; otherwise, returns `{UNWRAP_RECURSIVE}(o)`#. +*_Returns:_* [.underline]#`o`, where `o` denotes a reference to the object stored in `v`, if the type of the expression's receiver is a specialization of `{recursive_wrapper}`; otherwise, returns `{unwrap_recursive}(o)`#. [,cpp,subs="+macros,+attributes"] @@ -1040,7 +1039,7 @@ constexpr variant_alternative_t> const&& [.candidates] * [.candidate]#{empty}# *_Mandates:_* `I < sizeof\...(Ts)`. + -*_Effects:_* If `v.index()` is `I`, returns [.underline]#`{UNWRAP_RECURSIVE}(o)`, where `o` denotes a reference to the object stored in the `rvariant`#. Otherwise, throws an exception of type {bad-variant-access}. +*_Effects:_* If `v.index()` is `I`, returns [.underline]#`{unwrap_recursive}(o)`, where `o` denotes a reference to the object stored in the `rvariant`#. Otherwise, throws an exception of type {bad-variant-access}. [,cpp,subs="+macros,+attributes"] @@ -1056,9 +1055,9 @@ template constexpr T const&& get(rvariant const&& v ---- [.candidates] -* [.candidate]#{empty}# *_Mandates:_* The type `T` occurs exactly once in [.underline]#`{unwrap_recursive_t}`#. +* [.candidate]#{empty}# *_Mandates:_* The type `T` occurs exactly once in [.underline]#`{unwrap_recursive_type}`#. + -*_Effects:_* [.underline]#Let `VT` denote the type of the alternative held by `v`. If `{unwrap_recursive_t}` is the same type as `T`#, returns [.underline]#`{UNWRAP_RECURSIVE}(o)`, where `o` denotes a reference to the object stored in the `rvariant`#. Otherwise, throws an exception of type {bad-variant-access}. +*_Effects:_* [.underline]#Let `VT` denote the type of the alternative held by `v`. If `{unwrap_recursive_type}` is the same type as `T`#, returns [.underline]#`{unwrap_recursive}(o)`, where `o` denotes a reference to the object stored in the `rvariant`#. Otherwise, throws an exception of type {bad-variant-access}. + *_Remarks:_* [.underline]#This function is defined as deleted if `T` is a specialization of `{recursive_wrapper}`.# @@ -1081,7 +1080,7 @@ constexpr std::add_pointer_t> const> [.candidates] * [.candidate]#1-2)# *_Mandates:_* `I < sizeof\...(Ts)`. + -*_Returns:_* A pointer to the value [.underline]#denoted by `{UNWRAP_RECURSIVE}(o)`, where `o` denotes a reference to the object stored in the `rvariant`#, if `v != nullptr` and `v\->index() == I`. Otherwise, returns `nullptr`. +*_Returns:_* A pointer to the value [.underline]#denoted by `{unwrap_recursive}(o)`, where `o` denotes a reference to the object stored in the `rvariant`#, if `v != nullptr` and `v\->index() == I`. Otherwise, returns `nullptr`. [,cpp,subs="+macros,+attributes"] @@ -1100,9 +1099,9 @@ constexpr std::add_pointer_t ---- [.candidates] -* [.candidate]#1-2)# *_Mandates:_* The type `T` occurs exactly once in [.underline]#`{unwrap_recursive_t}`#. +* [.candidate]#1-2)# *_Mandates:_* The type `T` occurs exactly once in [.underline]#`{unwrap_recursive_type}`#. + -*_Effects:_* Equivalent to: `return get_if<__i__>(v);` with _i_ being the zero-based index of `T` in [.underline]#`{unwrap_recursive_t}`#. +*_Effects:_* Equivalent to: `return get_if<__i__>(v);` with _i_ being the zero-based index of `T` in [.underline]#`{unwrap_recursive_type}`#. + *_Remarks:_* [.underline]#This function is defined as deleted if `T` is a specialization of `{recursive_wrapper}`.# @@ -1135,7 +1134,7 @@ constexpr R visit(this Self&& self, Visitor&& vis);pass:quotes[[.candidate\]#// * [.candidate]#1-2)# Equivalent to the `std::variant` counterpart ^https://eel.is/c++draft/variant.visit[[spec\]]^, except that: + [none] -** -- `_GET_<__m__>(std::forward(vars))` is replaced with `{UNWRAP_RECURSIVE}(_GET_<__m__>(std::forward(vars)))`. +** -- `_GET_<__m__>(std::forward(vars))` is replaced with `{unwrap_recursive}(_GET_<__m__>(std::forward(vars)))`. * [.candidate]#3-4)# Equivalent to the `std::variant` counterpart ^https://eel.is/c++draft/variant.visit[[spec\]]^, except that it forwards to `temp_ns::visit` instead of `std::visit`. @@ -1216,13 +1215,13 @@ std::ostream& operator<<(std::ostream& os, rvariant const& v);pass:quotes ** -- the expression `os << val` is well-formed and has the type `std::ostream&`, and ** -- the corresponding overload is found solely via ADL. -* [.candidate]#2)# *_Constraints:_* `_ADL-ostreamable_<{unwrap_recursive_t}>` is `true` for all _i_. +* [.candidate]#2)# *_Constraints:_* `_ADL-ostreamable_<{unwrap_recursive_type}>` is `true` for all _i_. + *_Effects:_* Behaves as a formatted output function (https://eel.is/c++draft/ostream.formatted.reqmts[[ostream.formatted.reqmts\]]) of `os`, except that: + -- [none] -** -- the output is done as if by calling `os << {UNWRAP_RECURSIVE}(_GET_<__i__>(v))` (with _i_ being `v.index()`), and +** -- the output is done as if by calling `os << {unwrap_recursive}(_GET_<__i__>(v))` (with _i_ being `v.index()`), and ** -- any exception of type `std::bad_variant_access`, whether thrown directly (i.e., due to `v` being valueless) or indirectly (i.e., by a nested call to an alternative's output function), is propagated without regard to the value of `os.exceptions()` and without turning on `std::ios_base::badbit` in the error state of `os`. -- + @@ -1240,12 +1239,12 @@ std::ostream& operator<<(std::ostream& os, rvariant const& v);pass:quotes [none] * Let `v` denote an object of `rvariant`, and let `proxy` denote an object of `{variant-format-proxy}`. -* The specialization `std::formatter<::temp_ns::rvariant, charT>` (for arbitrary `charT`) is enabled if and only if `std::formattable<{unwrap_recursive_t}, charT>` is `true` for all _i_, with the following characteristics: +* The specialization `std::formatter<::temp_ns::rvariant, charT>` (for arbitrary `charT`) is enabled if and only if `std::formattable<{unwrap_recursive_type}, charT>` is `true` for all _i_, with the following characteristics: + [none] ** -- The format specifier must be empty, otherwise `std::format_error` is thrown, and ** -- if `v.valueless_by_exception()` is `true`, `std::bad_variant_access` is thrown, and -** -- the output is done as if by calling `std::format_to(fmt_ctx.out(), _paren_, {UNWRAP_RECURSIVE}(_GET_(v)))`, with `_paren_` being a string literal `"{}"` interpreted on the target character type. +** -- the output is done as if by calling `std::format_to(fmt_ctx.out(), _paren_, {unwrap_recursive}(_GET_(v)))`, with `_paren_` being a string literal `"{}"` interpreted on the target character type. ** _Example:_ + [,cpp,subs="+macros,+attributes"] @@ -1258,14 +1257,14 @@ std::println("{}", temp_ns::rvariant(42)); // prints pass:quotes[`4 [none] ** -- `std::remove_cvref_t` is a specialization of `{variant-format-string}`, and ** -- `std::remove_cvref_t` is a specialization of `rvariant`, and -** -- `std::formattable<{unwrap_recursive_t}, charT>` is `true` for all _i_, with `Ts` being the template parameter pack of cv-unqualified non-reference type for `Variant`. +** -- `std::formattable<{unwrap_recursive_type}, charT>` is `true` for all _i_, with `Ts` being the template parameter pack of cv-unqualified non-reference type for `Variant`. * It has the following characteristics: + [none] ** -- The format specifier must be empty, otherwise `std::format_error` is thrown, and ** -- if `v.valueless_by_exception()` is `true`, `std::bad_variant_access` is thrown, and -** -- the output is done as if by calling `std::format_to(fmt_ctx.out(), proxy.v_fmt(std::in_place_type), {UNWRAP_RECURSIVE}(_GET_(proxy.v)))`, with `Ts` being the template parameter pack of the cv-unqualified non-reference type of `proxy.v`. +** -- the output is done as if by calling `std::format_to(fmt_ctx.out(), proxy.v_fmt(std::in_place_type), {unwrap_recursive}(_GET_(proxy.v)))`, with `Ts` being the template parameter pack of the cv-unqualified non-reference type of `proxy.v`. ** _Example:_ + [,cpp,subs="+macros,+attributes"] @@ -1453,35 +1452,35 @@ _Note 2:_ It is currently unknown whether the recursive instantiation scenario d [[rvariant.recursive.helper]] -== `recursive_wrapper` helper classes [.slug]##<>## +== `recursive_wrapper` helper utilities [.slug]##<>## [,cpp,subs="+macros,+attributes"] ---- namespace temp_ns { template -struct unwrap_recursive -{ - using type = T; -}; - -template -struct unwrap_recursive> -{ - using type = T; -}; +using unwrap_recursive_type = {see-below}; } // temp_ns ---- +[.candidates] +* [.candidate]#{empty}# Denotes `T::value_type` if `T` is a specialization of `{recursive_wrapper}`. Otherwise, denotes `T`. + [,cpp,subs="+macros,+attributes"] ---- +namespace temp_ns { + template -constexpr {see-below} pass:quotes[_UNWRAP_RECURSIVE_](T&& o) noexcept; // {exposition-only} +constexpr auto&& unwrap_recursive(T&& o) noexcept; + +} // temp_ns ---- [.candidates] -* [.candidate]#{empty}# *_Effects:_* Denotes `*o`, if cv-unqualified non-reference type for `T` is a specialization of `{recursive_wrapper}`. Otherwise, denotes `o`. +* [.candidate]#{empty}# *_Returns:_* `*o`, if cv-unqualified non-reference type for `T` is a specialization of `{recursive_wrapper}`. Otherwise, returns `o`. ++ +*_Remarks:_* `unwrap_recursive` is an _algorithm function object_ (link:https://eel.is/c++draft/alg.func.obj[[alg.func.obj\],window=_blank]). [[rvariant.pack]] @@ -1507,7 +1506,7 @@ struct compact_alternative; A variant with a single alternative may introduce unnecessary overhead when used in many places where only the underlying type is actually needed. In such cases, the variant can be _unwrapped_ using `compact_alternative`. This is useful for resolving issues such as https://github.com/boostorg/spirit/issues/610[boostorg/spirit#610]. [WARNING] -`compact_alternative` does not unwrap `{recursive_wrapper}`. This is intentional, because doing so could lead to instantiating incomplete type on undesired timings. You may apply `{unwrap_recursive_t}` manually. +`compact_alternative` does not unwrap `{recursive_wrapper}`. This is intentional, because doing so could lead to instantiating incomplete type on undesired timings. You may apply `{unwrap_recursive_type}` manually. [[rvariant.xo]] diff --git a/doc/rvariant.html b/doc/rvariant.html index a79dfc8..71e11eb 100644 --- a/doc/rvariant.html +++ b/doc/rvariant.html @@ -904,7 +904,7 @@

rvariantConstructors -
  • recursive_wrapper helper classes [rvariant.recursive.helper]
  • +
  • recursive_wrapper helper utilities [rvariant.recursive.helper]
  • Pack manipulation and deduping [rvariant.pack]
  • Exposition-only utilities [rvariant.xo]
      @@ -956,7 +956,7 @@

      Supported Environments

      Clang 21-22 (libc++)

    • -

      MSVC (2022)

      +

      MSVC 2022 and 2026

    • C++23 and C++26

      @@ -1343,9 +1343,8 @@

      Header <temp /* constexpr */ std::size_t hash_value(recursive_wrapper<T, Allocator> const&); // [rvariant.recursive.helper], recursive_wrapper helper classes -template<class T> struct unwrap_recursive; -template<class T, class Allocator> struct unwrap_recursive<recursive_wrapper<T, Allocator>>; -template<class T> using unwrap_recursive_t = typename unwrap_recursive<T>::type; +template<class T> using unwrap_recursive_type = see below; +template<class T> constexpr auto&& unwrap_recursive(T&& o) noexcept; // [rvariant.pack], pack manipulation and deduping template<template<class...> class TT, class A, class B> @@ -1508,7 +1507,7 @@

      • -

        Let VTi denote recursive_wrapper<Ti, A> (for any type A) if such a specialization occurs anywhere in Ts...; otherwise, let VTi denote Ti. Let Uj denote the jth type of the template parameter pack having the name Us on each flexibility-related functions. The corresponding alternative for rvariant is the first type for which std::is_same_v<unwrap_recursive_t<VTi>, unwrap_recursive_t<Uj>> is true.

        +

        Let VTi denote recursive_wrapper<Ti, A> (for any type A) if such a specialization occurs anywhere in Ts...; otherwise, let VTi denote Ti. Let Uj denote the jth type of the template parameter pack having the name Us on each flexibility-related functions. The corresponding alternative for rvariant is the first type for which std::is_same_v<unwrap_recursive_type<VTi>, unwrap_recursive_type<Uj>> is true.

      @@ -1557,7 +1556,7 @@

      Constructors
    • 4) Generic constructor. Equivalent to the std::variant counterpart, [spec] except:

      -

      Postconditions: holds_alternative<unwrap_recursive_t<Tj>>(*this) is true.

      +

      Postconditions: holds_alternative<unwrap_recursive_type<Tj>>(*this) is true.

    • @@ -1573,7 +1572,7 @@

      Constructors
      • -

         — There is exactly one occurrence of T in unwrap_recursive_t<Ts>... and

        +

         — There is exactly one occurrence of T in unwrap_recursive_type<Ts>... and

      •  — std::is_constructible_v<VT, Args...> is true.

        @@ -1608,7 +1607,7 @@

        Constructors
        • -

           — There is exactly one occurrence of T in unwrap_recursive_t<Ts>... and

          +

           — There is exactly one occurrence of T in unwrap_recursive_type<Ts>... and

        •  — std::is_constructible_v<VT, std::initializer_list<U>&, Args...> is true.

          @@ -1653,7 +1652,7 @@

          Constructors

           — rvariant_set::subset_of<rvariant<Us...>, rvariant> is true, and

        • -

           — std::disjunction_v<std::is_same<rvariant<Us...>, unwrap_recursive_t<Ts>>...> is false, and

          +

           — std::disjunction_v<std::is_same<rvariant<Us...>, unwrap_recursive_type<Ts>>...> is false, and

        •  — std::is_constructible_v<VTi, Uj const&> is true for all j.

          @@ -1698,7 +1697,7 @@

          Constructors

           — rvariant_set::subset_of<rvariant<Us...>, rvariant> is true, and

        • -

           — std::disjunction_v<std::is_same<rvariant<Us...>, unwrap_recursive_t<Ts>>...> is false, and

          +

           — std::disjunction_v<std::is_same<rvariant<Us...>, unwrap_recursive_type<Ts>>...> is false, and

        •  — std::is_constructible_v<VTi, Uj&&> is true for all j.

          @@ -1776,7 +1775,7 @@

          Assignmen
        • 3) Generic assignment operator. Equivalent to the std::variant counterpart, [spec] except:

          -

          Postconditions: holds_alternative<unwrap_recursive_t<Tj>>(*this) is true, with Tj selected by the imaginary function overload resolution described above.

          +

          Postconditions: holds_alternative<unwrap_recursive_type<Tj>>(*this) is true, with Tj selected by the imaginary function overload resolution described above.

        • @@ -1798,7 +1797,7 @@

          Assignmen

           — rvariant_set::subset_of<rvariant<Us...>, rvariant> is true, and

        • -

           — std::disjunction_v<std::is_same<rvariant<Us...>, unwrap_recursive_t<Ts>>...> is false, and

          +

           — std::disjunction_v<std::is_same<rvariant<Us...>, unwrap_recursive_type<Ts>>...> is false, and

        •  — std::is_constructible_v<VTi, Uj const&> && std::is_assignable_v<VTi&, Uj const&> is true for all j.

          @@ -1824,7 +1823,7 @@

          Assignmen

           — Otherwise, if rhs holds a value but *this does not, initializes rvariant to hold VTi (with i being the index of the alternative corresponding to that of rhs) and direct-initializes the contained value with GET<j>(rhs).

        • -

           — Otherwise, if std::is_same_v<unwrap_recursive_t<Ti>, unwrap_recursive_t<Uj>> is true, assigns GET<j>(rhs) to the value contained in *this. (Note: the left hand side is Ti, not VTi. This ensures that the existing storage is reused even for rvariant with duplicate corresponding alternatives; i.e., index() is unchanged.)

          +

           — Otherwise, if std::is_same_v<unwrap_recursive_type<Ti>, unwrap_recursive_type<Uj>> is true, assigns GET<j>(rhs) to the value contained in *this. (Note: the left hand side is Ti, not VTi. This ensures that the existing storage is reused even for rvariant with duplicate corresponding alternatives; i.e., index() is unchanged.)

        •  — Otherwise, if either std::is_nothrow_constructible_v<VTi, Uj const&> is true or std::is_nothrow_move_constructible_v<VTi> is false, equivalent to emplace<VTi>(GET<j>(rhs)).

          @@ -1865,7 +1864,7 @@

          Assignmen

           — rvariant_set::subset_of<rvariant<Us...>, rvariant> is true, and

        • -

           — std::disjunction_v<std::is_same<rvariant<Us...>, unwrap_recursive_t<Ts>>...> is false, and

          +

           — std::disjunction_v<std::is_same<rvariant<Us...>, unwrap_recursive_type<Ts>>...> is false, and

        •  — std::is_constructible_v<VTi, Uj&&> && std::is_assignable_v<VTi&, Uj&&> is true for all j.

          @@ -1891,7 +1890,7 @@

          Assignmen

           — Otherwise, if rhs holds a value but *this does not, initializes rvariant to hold VTi (with i being the index of the alternative corresponding to that of rhs) and direct-initializes the contained value with GET<j>(std::move(rhs)).

        • -

           — Otherwise, if std::is_same_v<unwrap_recursive_t<Ti>, unwrap_recursive_t<Uj>> is true, assigns GET<j>(std::move(rhs)) to the value contained in *this. (Note: the left hand side is Ti, not VTi. This ensures that the existing storage is reused even for rvariant with duplicate corresponding alternatives; i.e., index() is unchanged.)

          +

           — Otherwise, if std::is_same_v<unwrap_recursive_type<Ti>, unwrap_recursive_type<Uj>> is true, assigns GET<j>(std::move(rhs)) to the value contained in *this. (Note: the left hand side is Ti, not VTi. This ensures that the existing storage is reused even for rvariant with duplicate corresponding alternatives; i.e., index() is unchanged.)

        •  — Otherwise, equivalent to emplace<VTi>(GET<j>(std::move(rhs))).

          @@ -1937,12 +1936,12 @@

          Modifiers Mandates: T is not a specialization of recursive_wrapper.

        -

        Constraints: std::is_constructible_v<VT, Args...> is true, and T occurs exactly once in unwrap_recursive_t<Ts>.

        +

        Constraints: std::is_constructible_v<VT, Args...> is true, and T occurs exactly once in unwrap_recursive_type<Ts>.

        Effects: Equivalent to:
          return emplace<I>(std::forward<Args>(args)...);
        -where I is the zero-based index of T in unwrap_recursive_t<Ts>.

        +where I is the zero-based index of T in unwrap_recursive_type<Ts>.

      • @@ -1951,18 +1950,18 @@

        Modifiers Mandates: T is not a specialization of recursive_wrapper.

      -

      Constraints: std::is_constructible_v<VT, std::initializer_list<U>&, Args...> is true, and T occurs exactly once in unwrap_recursive_t<Ts>.

      +

      Constraints: std::is_constructible_v<VT, std::initializer_list<U>&, Args...> is true, and T occurs exactly once in unwrap_recursive_type<Ts>.

      Effects: Equivalent to:
        return emplace<I>(il, std::forward<Args>(args)...);
      -where I is the zero-based index of T in unwrap_recursive_t<Ts>.

      +where I is the zero-based index of T in unwrap_recursive_type<Ts>.

    • 3) Equivalent to the std::variant counterpart, [spec] except:

      -

      Returns: Let o denote a reference to the new contained value. Returns UNWRAP_RECURSIVE(o).

      +

      Returns: Let o denote a reference to the new contained value. Returns unwrap_recursive(o).

      Remarks: If TI is a specialization of recursive_wrapper, this function is permitted to construct an intermediate variable tmp as if by passing std::forward<Args>(args)... to TI's constructor. Then rvariant direct-non-list-initializes the contained value of TI with the argument std::move(tmp). (Note: This allows optimization where rvariant can be assumed to become never valueless on certain cases.)

      @@ -1971,7 +1970,7 @@

      Modifiers

      4) Equivalent to the std::variant counterpart, [spec] except:

      -

      Returns: Let o denote a reference to the new contained value. Returns UNWRAP_RECURSIVE(o).

      +

      Returns: Let o denote a reference to the new contained value. Returns unwrap_recursive(o).

      Remarks: If TI is a specialization of recursive_wrapper, this function is permitted to construct an intermediate variable tmp as if by passing il, std::forward<Args>(args)... to TI's constructor. Then rvariant direct-non-list-initializes the contained value of TI with the argument std::move(tmp). (Note: This allows optimization where rvariant can be assumed to become never valueless on certain cases.)

      @@ -2122,7 +2121,7 @@

      rva Equivalent to the std::variant counterpart. [spec]

    • -

      2) The member typedef type denotes unwrap_recursive_t<TI>.

      +

      2) The member typedef type denotes unwrap_recursive_type<TI>.

      Mandates: I < sizeof...(Ts).

      @@ -2169,7 +2168,7 @@

      Flexibility t

       — T is the same type as U or,

    • -

       — unwrap_recursive_t<T> is the same type as U.

      +

       — unwrap_recursive_type<T> is the same type as U.

    @@ -2194,9 +2193,9 @@

    Value access
    • -

      Mandates: The type T occurs exactly once in unwrap_recursive_t<Ts>.

      +

      Mandates: The type T occurs exactly once in unwrap_recursive_type<Ts>.

      -

      Returns: true if v.index() is equal to the zero-based index of T in unwrap_recursive_t<Ts>.

      +

      Returns: true if v.index() is equal to the zero-based index of T in unwrap_recursive_type<Ts>.

      Remarks: This function is defined as deleted if T is a specialization of recursive_wrapper.

      @@ -2227,7 +2226,7 @@

      Value access Preconditions: v.index() is I.

      -

      Returns: o, where o denotes a reference to the object stored in v, if the type of the expression’s receiver is a specialization of recursive_wrapper; otherwise, returns UNWRAP_RECURSIVE(o).

      +

      Returns: o, where o denotes a reference to the object stored in v, if the type of the expression’s receiver is a specialization of recursive_wrapper; otherwise, returns unwrap_recursive(o).

    @@ -2260,7 +2259,7 @@

    Value access

    Mandates: I < sizeof...(Ts).

    -

    Effects: If v.index() is I, returns UNWRAP_RECURSIVE(o), where o denotes a reference to the object stored in the rvariant. Otherwise, throws an exception of type std::bad_variant_access.

    +

    Effects: If v.index() is I, returns unwrap_recursive(o), where o denotes a reference to the object stored in the rvariant. Otherwise, throws an exception of type std::bad_variant_access.

  • @@ -2280,9 +2279,9 @@

    Value access
    • -

      Mandates: The type T occurs exactly once in unwrap_recursive_t<Ts>.

      +

      Mandates: The type T occurs exactly once in unwrap_recursive_type<Ts>.

      -

      Effects: Let VT denote the type of the alternative held by v. If unwrap_recursive_t<VT> is the same type as T, returns UNWRAP_RECURSIVE(o), where o denotes a reference to the object stored in the rvariant. Otherwise, throws an exception of type std::bad_variant_access.

      +

      Effects: Let VT denote the type of the alternative held by v. If unwrap_recursive_type<VT> is the same type as T, returns unwrap_recursive(o), where o denotes a reference to the object stored in the rvariant. Otherwise, throws an exception of type std::bad_variant_access.

      Remarks: This function is defined as deleted if T is a specialization of recursive_wrapper.

      @@ -2310,7 +2309,7 @@

      Value access

      1-2) Mandates: I < sizeof...(Ts).

      -

      Returns: A pointer to the value denoted by UNWRAP_RECURSIVE(o), where o denotes a reference to the object stored in the rvariant, if v != nullptr and v->index() == I. Otherwise, returns nullptr.

      +

      Returns: A pointer to the value denoted by unwrap_recursive(o), where o denotes a reference to the object stored in the rvariant, if v != nullptr and v->index() == I. Otherwise, returns nullptr.

    @@ -2333,9 +2332,9 @@

    Value access
    • -

      1-2) Mandates: The type T occurs exactly once in unwrap_recursive_t<Ts>.

      +

      1-2) Mandates: The type T occurs exactly once in unwrap_recursive_type<Ts>.

      -

      Effects: Equivalent to: return get_if<i>(v); with i being the zero-based index of T in unwrap_recursive_t<Ts>.

      +

      Effects: Equivalent to: return get_if<i>(v); with i being the zero-based index of T in unwrap_recursive_type<Ts>.

      Remarks: This function is defined as deleted if T is a specialization of recursive_wrapper.

      @@ -2376,7 +2375,7 @@

      Visitation
      • -

         — GET<m>(std::forward<V>(vars)) is replaced with UNWRAP_RECURSIVE(GET<m>(std::forward<V>(vars))).

        +

         — GET<m>(std::forward<V>(vars)) is replaced with unwrap_recursive(GET<m>(std::forward<V>(vars))).

      @@ -2489,7 +2488,7 @@

      <

    • -

      2) Constraints: ADL-ostreamable<unwrap_recursive_t<Ti>> is true for all i.

      +

      2) Constraints: ADL-ostreamable<unwrap_recursive_type<Ti>> is true for all i.

      Effects: Behaves as a formatted output function ([ostream.formatted.reqmts]) of os, except that:

      @@ -2498,7 +2497,7 @@

      <
      • -

         — the output is done as if by calling os << UNWRAP_RECURSIVE(GET<i>(v)) (with i being v.index()), and

        +

         — the output is done as if by calling os << unwrap_recursive(GET<i>(v)) (with i being v.index()), and

      •  — any exception of type std::bad_variant_access, whether thrown directly (i.e., due to v being valueless) or indirectly (i.e., by a nested call to an alternative’s output function), is propagated without regard to the value of os.exceptions() and without turning on std::ios_base::badbit in the error state of os.

        @@ -2525,7 +2524,7 @@

        Let v denote an object of rvariant, and let proxy denote an object of variant_format_proxy.

      • -

        The specialization std::formatter<::temp_ns::rvariant<Ts...>, charT> (for arbitrary charT) is enabled if and only if std::formattable<unwrap_recursive_t<Tsi>, charT> is true for all i, with the following characteristics:

        +

        The specialization std::formatter<::temp_ns::rvariant<Ts...>, charT> (for arbitrary charT) is enabled if and only if std::formattable<unwrap_recursive_type<Tsi>, charT> is true for all i, with the following characteristics:

        • @@ -2535,7 +2534,7 @@

           — if v.valueless_by_exception() is true, std::bad_variant_access is thrown, and

        • -

           — the output is done as if by calling std::format_to(fmt_ctx.out(), paren, UNWRAP_RECURSIVE(GET<v.index()>(v))), with paren being a string literal "{}" interpreted on the target character type.

          +

           — the output is done as if by calling std::format_to(fmt_ctx.out(), paren, unwrap_recursive(GET<v.index()>(v))), with paren being a string literal "{}" interpreted on the target character type.

        • Example:

          @@ -2559,7 +2558,7 @@

           — std::remove_cvref_t<Variant> is a specialization of rvariant, and

        • -

           — std::formattable<unwrap_recursive_t<Tsi>, charT> is true for all i, with Ts being the template parameter pack of cv-unqualified non-reference type for Variant.

          +

           — std::formattable<unwrap_recursive_type<Tsi>, charT> is true for all i, with Ts being the template parameter pack of cv-unqualified non-reference type for Variant.

        @@ -2575,7 +2574,7 @@

         — if v.valueless_by_exception() is true, std::bad_variant_access is thrown, and

      • -

         — the output is done as if by calling std::format_to(fmt_ctx.out(), proxy.v_fmt(std::in_place_type<Ts...[proxy.v.index()]>), UNWRAP_RECURSIVE(GET<proxy.v.index()>(proxy.v))), with Ts being the template parameter pack of the cv-unqualified non-reference type of proxy.v.

        +

         — the output is done as if by calling std::format_to(fmt_ctx.out(), proxy.v_fmt(std::in_place_type<Ts...[proxy.v.index()]>), unwrap_recursive(GET<proxy.v.index()>(proxy.v))), with Ts being the template parameter pack of the cv-unqualified non-reference type of proxy.v.

      • Example:

        @@ -2834,37 +2833,42 @@

        -

        recursive_wrapper helper classes [rvariant.recursive.helper]

        +

        recursive_wrapper helper utilities [rvariant.recursive.helper]

        namespace temp_ns {
         
         template<class T>
        -struct unwrap_recursive
        -{
        -  using type = T;
        -};
        -
        -template<class T, class Allocator>
        -struct unwrap_recursive<recursive_wrapper<T, Allocator>>
        -{
        -  using type = T;
        -};
        +using unwrap_recursive_type = see below;
         
         } // temp_ns
        +
        +
          +
        • +

          Denotes T::value_type if T is a specialization of recursive_wrapper. Otherwise, denotes T.

          +
        • +
        +
        -
        template<class T>
        -constexpr see below UNWRAP_RECURSIVE(T&& o) noexcept; // exposition only
        +
        namespace temp_ns {
        +
        +template<class T>
        +constexpr auto&& unwrap_recursive(T&& o) noexcept;
        +
        +} // temp_ns
        • -

          Effects: Denotes *o, if cv-unqualified non-reference type for T is a specialization of recursive_wrapper. Otherwise, denotes o.

          +

          Returns: *o, if cv-unqualified non-reference type for T is a specialization of recursive_wrapper. Otherwise, returns o.

          +
          +

          Remarks: unwrap_recursive is an algorithm function object ([alg.func.obj]).

          +
        @@ -2913,7 +2917,7 @@

        Pack manipula -compact_alternative does not unwrap recursive_wrapper. This is intentional, because doing so could lead to instantiating incomplete type on undesired timings. You may apply unwrap_recursive_t manually. +compact_alternative does not unwrap recursive_wrapper. This is intentional, because doing so could lead to instantiating incomplete type on undesired timings. You may apply unwrap_recursive_type manually. diff --git a/include/iris/rvariant/detail/visit.hpp b/include/iris/rvariant/detail/visit.hpp index 78f878c..5db14b5 100644 --- a/include/iris/rvariant/detail/visit.hpp +++ b/include/iris/rvariant/detail/visit.hpp @@ -1,4 +1,4 @@ -#ifndef IRIS_RVARIANT_DETAIL_VISIT_HPP +#ifndef IRIS_RVARIANT_DETAIL_VISIT_HPP #define IRIS_RVARIANT_DETAIL_VISIT_HPP // SPDX-License-Identifier: MIT @@ -306,16 +306,16 @@ struct visit_check_impl> template struct visit_check_impl, rvariant&, Rest...> - : std::conjunction&>, Rest...>...> {}; + : std::conjunction&>, Rest...>...> {}; template struct visit_check_impl, rvariant const&, Rest...> - : std::conjunction const&>, Rest...>...> {}; + : std::conjunction const&>, Rest...>...> {}; template struct visit_check_impl, rvariant&&, Rest...> - : std::conjunction>, Rest...>...> {}; + : std::conjunction>, Rest...>...> {}; template struct visit_check_impl, rvariant const&&, Rest...> - : std::conjunction const>, Rest...>...> {}; + : std::conjunction const>, Rest...>...> {}; template using visit_check = visit_check_impl, Variants...>; @@ -357,16 +357,16 @@ struct visit_R_check_impl> template struct visit_R_check_impl, rvariant&, Rest...> - : std::conjunction&>, Rest...>...> {}; + : std::conjunction&>, Rest...>...> {}; template struct visit_R_check_impl, rvariant const&, Rest...> - : std::conjunction const&>, Rest...>...> {}; + : std::conjunction const&>, Rest...>...> {}; template struct visit_R_check_impl, rvariant&&, Rest...> - : std::conjunction>, Rest...>...> {}; + : std::conjunction>, Rest...>...> {}; template struct visit_R_check_impl, rvariant const&&, Rest...> - : std::conjunction const>, Rest...>...> {}; + : std::conjunction const>, Rest...>...> {}; template using visit_R_check = visit_R_check_impl, Variants...>; @@ -387,7 +387,7 @@ struct multi_visit_noexcept, Visitor, Storage...> using type = std::is_nothrow_invocable_r< R, Visitor, - unwrap_recursive_t< + unwrap_recursive_type< detail::raw_get_t(Is), Storage_> >... >; diff --git a/include/iris/rvariant/rvariant.hpp b/include/iris/rvariant/rvariant.hpp index 6d59d3c..e05b2ca 100644 --- a/include/iris/rvariant/rvariant.hpp +++ b/include/iris/rvariant/rvariant.hpp @@ -420,7 +420,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN } }); } - return detail::unwrap_recursive(detail::raw_get(storage_)); + return unwrap_recursive(detail::raw_get(storage_)); } IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END @@ -493,7 +493,7 @@ class rvariant : private detail::rvariant_base_t static_assert((req::Cpp17Destructible && ...), "All types shall meet the Cpp17Destructible requirements ([variant.variant.general])."); static_assert(sizeof...(Ts) > 0, "A variant with no template arguments shall not be instantiated ([variant.variant.general])."); - using unwrapped_types = type_list...>; + using unwrapped_types = type_list...>; using base_type = detail::rvariant_base_t; friend struct detail::rvariant_base; @@ -586,18 +586,18 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END requires (!std::is_same_v, rvariant>) && rvariant_set::subset_of, rvariant> && - (!std::disjunction_v, unwrap_recursive_t>...>) && - std::conjunction_v, Ts...>, Us const&>...> + (!std::disjunction_v, unwrap_recursive_type>...>) && + std::conjunction_v, Ts...>, Us const&>...> constexpr rvariant(rvariant const& w) - noexcept(std::conjunction_v, Ts...>, Us const&>...>) + noexcept(std::conjunction_v, Ts...>, Us const&>...>) { w.raw_visit([this](std::in_place_index_t, [[maybe_unused]] Uj const& uj) - noexcept(std::conjunction_v, Ts...>, Us const&>...>) + noexcept(std::conjunction_v, Ts...>, Us const&>...>) { if constexpr (j != std::variant_npos) { - using maybe_wrapped = detail::select_maybe_wrapped, Ts...>; + using maybe_wrapped = detail::select_maybe_wrapped, Ts...>; using VT = maybe_wrapped::type; - static_assert(std::is_same_v, unwrap_recursive_t>); + static_assert(std::is_same_v, unwrap_recursive_type>); base_type::template construct_on_valueless(detail::forward_maybe_wrapped(uj)); } }); @@ -608,18 +608,18 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END requires (!std::is_same_v, rvariant>) && rvariant_set::subset_of, rvariant> && - (!std::disjunction_v, unwrap_recursive_t>...>) && - std::conjunction_v, Ts...>, Us&&>...> + (!std::disjunction_v, unwrap_recursive_type>...>) && + std::conjunction_v, Ts...>, Us&&>...> constexpr rvariant(rvariant&& w) - noexcept(std::conjunction_v, Ts...>, Us&&>...>) + noexcept(std::conjunction_v, Ts...>, Us&&>...>) { std::move(w).raw_visit([this](std::in_place_index_t, [[maybe_unused]] Uj&& uj) - noexcept(std::conjunction_v, Ts...>, Us&&>...>) + noexcept(std::conjunction_v, Ts...>, Us&&>...>) { if constexpr (j != std::variant_npos) { - using maybe_wrapped = detail::select_maybe_wrapped, Ts...>; + using maybe_wrapped = detail::select_maybe_wrapped, Ts...>; using VT = maybe_wrapped::type; - static_assert(std::is_same_v, unwrap_recursive_t>); + static_assert(std::is_same_v, unwrap_recursive_type>); static_assert(std::is_rvalue_reference_v); base_type::template construct_on_valueless(detail::forward_maybe_wrapped(std::move(uj))); // NOLINT(bugprone-move-forwarding-reference) } @@ -633,30 +633,30 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END requires (!std::is_same_v, rvariant>) && rvariant_set::subset_of, rvariant> && - (!std::disjunction_v, unwrap_recursive_t>...>) && - std::conjunction_v, Ts...>, Us const&>...> + (!std::disjunction_v, unwrap_recursive_type>...>) && + std::conjunction_v, Ts...>, Us const&>...> constexpr rvariant& operator=(rvariant const& rhs) - noexcept(std::conjunction_v, Ts...>, Us const&>...>) + noexcept(std::conjunction_v, Ts...>, Us const&>...>) { rhs.raw_visit([this](std::in_place_index_t, [[maybe_unused]] Uj const& uj) - noexcept(std::conjunction_v, Ts...>, Us const&>...>) + noexcept(std::conjunction_v, Ts...>, Us const&>...>) { if constexpr (j == std::variant_npos) { this->visit_reset(); } else { - using maybe_wrapped = detail::select_maybe_wrapped, Ts...>; + using maybe_wrapped = detail::select_maybe_wrapped, Ts...>; using VT = maybe_wrapped::type; - static_assert(std::is_same_v, unwrap_recursive_t>); + static_assert(std::is_same_v, unwrap_recursive_type>); this->raw_visit([this, &uj](std::in_place_index_t, [[maybe_unused]] Ti& ti) - noexcept(std::conjunction_v, Ts...>, Us const&>...>) + noexcept(std::conjunction_v, Ts...>, Us const&>...>) { constexpr std::size_t VTi = maybe_wrapped::index; if constexpr (i == std::variant_npos) { // this is valueless, rhs holds value base_type::template construct_on_valueless(detail::forward_maybe_wrapped(uj)); - } else if constexpr (std::is_same_v, unwrap_recursive_t>) { + } else if constexpr (std::is_same_v, unwrap_recursive_type>) { ti = detail::forward_maybe_wrapped(uj); } else if constexpr (std::is_nothrow_constructible_v || !std::is_nothrow_move_constructible_v) { @@ -677,31 +677,31 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END requires (!std::is_same_v, rvariant>) && rvariant_set::subset_of, rvariant> && - (!std::disjunction_v, unwrap_recursive_t>...>) && - std::conjunction_v, Ts...>, Us&&>...> + (!std::disjunction_v, unwrap_recursive_type>...>) && + std::conjunction_v, Ts...>, Us&&>...> constexpr rvariant& operator=(rvariant&& rhs) - noexcept(std::conjunction_v, Ts...>, Us&&>...>) + noexcept(std::conjunction_v, Ts...>, Us&&>...>) { std::move(rhs).raw_visit([this](std::in_place_index_t, [[maybe_unused]] Uj&& uj) - noexcept(std::conjunction_v, Ts...>, Us&&>...>) + noexcept(std::conjunction_v, Ts...>, Us&&>...>) { if constexpr (j == std::variant_npos) { this->visit_reset(); } else { - using maybe_wrapped = detail::select_maybe_wrapped, Ts...>; + using maybe_wrapped = detail::select_maybe_wrapped, Ts...>; using VT = maybe_wrapped::type; - static_assert(std::is_same_v, unwrap_recursive_t>); + static_assert(std::is_same_v, unwrap_recursive_type>); this->raw_visit([this, &uj](std::in_place_index_t, [[maybe_unused]] Ti& ti) - noexcept(std::conjunction_v, Ts...>, Us&&>...>) + noexcept(std::conjunction_v, Ts...>, Us&&>...>) { static_assert(std::is_rvalue_reference_v); constexpr std::size_t VTi = maybe_wrapped::index; if constexpr (i == std::variant_npos) { // this is valueless, rhs holds value base_type::template construct_on_valueless(detail::forward_maybe_wrapped(std::move(uj))); // NOLINT(bugprone-move-forwarding-reference) - } else if constexpr (std::is_same_v, unwrap_recursive_t>) { + } else if constexpr (std::is_same_v, unwrap_recursive_type>) { ti = detail::forward_maybe_wrapped(std::move(uj)); // NOLINT(bugprone-move-forwarding-reference) } else { @@ -1113,7 +1113,7 @@ get(rvariant& v IRIS_LIFETIMEBOUND) { static_assert(I < sizeof...(Ts)); if (v.index() == I) { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage&>(v))); } detail::throw_bad_variant_access(); } @@ -1124,7 +1124,7 @@ get(rvariant&& v IRIS_LIFETIMEBOUND) // NOLINT(cppcoreguidelines-rvalue- { static_assert(I < sizeof...(Ts)); if (v.index() == I) { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage&&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage&&>(v))); } detail::throw_bad_variant_access(); } @@ -1135,7 +1135,7 @@ get(rvariant const& v IRIS_LIFETIMEBOUND) { static_assert(I < sizeof...(Ts)); if (v.index() == I) { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage const&>(v))); } detail::throw_bad_variant_access(); } @@ -1146,7 +1146,7 @@ get(rvariant const&& v IRIS_LIFETIMEBOUND) { static_assert(I < sizeof...(Ts)); if (v.index() == I) { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage const&&>(v))); } detail::throw_bad_variant_access(); } @@ -1157,7 +1157,7 @@ get(rvariant& v IRIS_LIFETIMEBOUND) { constexpr std::size_t I = detail::exactly_once_index_v>; if (v.index() == I) { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage&>(v))); } detail::throw_bad_variant_access(); } @@ -1168,7 +1168,7 @@ get(rvariant&& v IRIS_LIFETIMEBOUND) // NOLINT(cppcoreguidelines-rvalue- { constexpr std::size_t I = detail::exactly_once_index_v>; if (v.index() == I) { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage&&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage&&>(v))); } detail::throw_bad_variant_access(); } @@ -1179,7 +1179,7 @@ get(rvariant const& v IRIS_LIFETIMEBOUND) { constexpr std::size_t I = detail::exactly_once_index_v>; if (v.index() == I) { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage const&>(v))); } detail::throw_bad_variant_access(); } @@ -1190,7 +1190,7 @@ get(rvariant const&& v IRIS_LIFETIMEBOUND) { constexpr std::size_t I = detail::exactly_once_index_v>; if (v.index() == I) { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage const&&>(v))); } detail::throw_bad_variant_access(); } @@ -1218,7 +1218,7 @@ template unsafe_get(rvariant& v IRIS_LIFETIMEBOUND) noexcept { static_assert(I < sizeof...(Ts)); - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage&>(v))); } template @@ -1226,7 +1226,7 @@ template unsafe_get(rvariant&& v IRIS_LIFETIMEBOUND) noexcept // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) { static_assert(I < sizeof...(Ts)); - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage&&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage&&>(v))); } template @@ -1234,14 +1234,14 @@ template unsafe_get(rvariant const& v IRIS_LIFETIMEBOUND) noexcept { static_assert(I < sizeof...(Ts)); - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage const&>(v))); } template [[nodiscard]] constexpr variant_alternative_t> const&& unsafe_get(rvariant const&& v IRIS_LIFETIMEBOUND) noexcept { - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage const&&>(v))); } template @@ -1249,7 +1249,7 @@ template unsafe_get(rvariant& v IRIS_LIFETIMEBOUND) noexcept { constexpr std::size_t I = detail::exactly_once_index_v>; - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage&>(v))); } template @@ -1257,7 +1257,7 @@ template unsafe_get(rvariant&& v IRIS_LIFETIMEBOUND) noexcept // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) { constexpr std::size_t I = detail::exactly_once_index_v>; - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage&&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage&&>(v))); } template @@ -1265,7 +1265,7 @@ template unsafe_get(rvariant const& v IRIS_LIFETIMEBOUND) noexcept { constexpr std::size_t I = detail::exactly_once_index_v>; - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage const&>(v))); } template @@ -1273,7 +1273,7 @@ template unsafe_get(rvariant const&& v IRIS_LIFETIMEBOUND) noexcept { constexpr std::size_t I = detail::exactly_once_index_v>; - return detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&&>(v))); + return unwrap_recursive(detail::raw_get(detail::forward_storage const&&>(v))); } template @@ -1300,7 +1300,7 @@ get_if(rvariant* v) noexcept { static_assert(I < sizeof...(Ts)); return v && v->index() == I - ? std::addressof(detail::unwrap_recursive(detail::raw_get(detail::forward_storage&>(*v)))) + ? std::addressof(unwrap_recursive(detail::raw_get(detail::forward_storage&>(*v)))) : nullptr; } @@ -1310,7 +1310,7 @@ get_if(rvariant const* v) noexcept { static_assert(I < sizeof...(Ts)); return v && v->index() == I - ? std::addressof(detail::unwrap_recursive(detail::raw_get(detail::forward_storage const&>(*v)))) + ? std::addressof(unwrap_recursive(detail::raw_get(detail::forward_storage const&>(*v)))) : nullptr; } diff --git a/include/iris/rvariant/rvariant_io.hpp b/include/iris/rvariant/rvariant_io.hpp index b90c0aa..1066ff0 100644 --- a/include/iris/rvariant/rvariant_io.hpp +++ b/include/iris/rvariant/rvariant_io.hpp @@ -46,7 +46,7 @@ template // Required to work around MSVC bug where it instantiates this function // for completely irrelevant call, e.g. `std::cout << "foo"sv << 'c' << std::endl;` (sizeof...(Ts) > 0) && - std::conjunction_v>...> + std::conjunction_v>...> std::ostream& operator<<(std::ostream& os, rvariant const& v) { std::ostream::sentry sentry(os); @@ -65,7 +65,7 @@ std::ostream& operator<<(std::ostream& os, rvariant const& v) if constexpr (i == std::variant_npos) { std::unreachable(); } else { - os << detail::unwrap_recursive(o); // NOTE: this may also throw `std::bad_variant_access` + os << unwrap_recursive(o); // NOTE: this may also throw `std::bad_variant_access` } }); @@ -181,7 +181,7 @@ struct variant_alts_formattable : std::false_type template struct variant_alts_formattable> - : std::bool_constant<(std::formattable, charT> && ...)> + : std::bool_constant<(std::formattable, charT> && ...)> {}; } // detail @@ -192,7 +192,7 @@ struct variant_alts_formattable> namespace std { template - requires (std::formattable<::iris::unwrap_recursive_t, charT> && ...) + requires (std::formattable<::iris::unwrap_recursive_type, charT> && ...) struct formatter<::iris::rvariant, charT> // NOLINT(cert-dcl58-cpp) { static constexpr typename std::basic_format_parse_context::const_iterator @@ -219,8 +219,8 @@ struct formatter<::iris::rvariant, charT> // NOLINT(cert-dcl58-cpp) } else { return std::format_to( ctx.out(), - ::iris::format_traits::template brace_full<::iris::unwrap_recursive_t const&>, - ::iris::detail::unwrap_recursive(alt) + ::iris::format_traits::template brace_full<::iris::unwrap_recursive_type const&>, + ::iris::unwrap_recursive(alt) ); } } @@ -257,13 +257,13 @@ struct formatter<::iris::detail::variant_format_proxy, charT> ::iris::detail::throw_bad_variant_access(); } else { static_assert( - std::is_invocable_v>>, + std::is_invocable_v>>, "`VFormat` must provide format string for all alternative types." ); return std::format_to( ctx.out(), - std::invoke(proxy.v_fmt, std::in_place_type<::iris::unwrap_recursive_t>), - ::iris::detail::unwrap_recursive(alt) + std::invoke(proxy.v_fmt, std::in_place_type<::iris::unwrap_recursive_type>), + ::iris::unwrap_recursive(alt) ); } } diff --git a/include/iris/rvariant/subset.hpp b/include/iris/rvariant/subset.hpp index 398ba18..fea2c49 100644 --- a/include/iris/rvariant/subset.hpp +++ b/include/iris/rvariant/subset.hpp @@ -47,7 +47,7 @@ struct is_subset_of, rvariant> : std::conjunction< std::disjunction< is_in, - is_in...> + is_in...> >... > {}; diff --git a/include/iris/rvariant/variant_helper.hpp b/include/iris/rvariant/variant_helper.hpp index af99ff4..840dc51 100644 --- a/include/iris/rvariant/variant_helper.hpp +++ b/include/iris/rvariant/variant_helper.hpp @@ -1,4 +1,4 @@ -#ifndef IRIS_RVARIANT_VARIANT_HELPER_HPP +#ifndef IRIS_RVARIANT_VARIANT_HELPER_HPP #define IRIS_RVARIANT_VARIANT_HELPER_HPP // SPDX-License-Identifier: MIT @@ -70,21 +70,37 @@ struct variant_size> : std::integral_constant -[[nodiscard]] IRIS_FORCEINLINE constexpr auto&& -unwrap_recursive(T&& o IRIS_LIFETIMEBOUND) noexcept +struct unwrap_recursive_type_impl { - if constexpr (is_ttp_specialization_of_v, recursive_wrapper>) { - return *std::forward(o); - } else { - return std::forward(o); + using type = T; +}; + +template +struct unwrap_recursive_type_impl> +{ + using type = T; +}; + +struct unwrap_recursive_fn +{ + template + [[nodiscard]] IRIS_FORCEINLINE static constexpr auto&& + operator()(T&& o IRIS_LIFETIMEBOUND) noexcept + { + if constexpr (is_ttp_specialization_of_v, recursive_wrapper>) { + return *std::forward(o); + } else { + return std::forward(o); + } } -} +}; } // detail -template struct unwrap_recursive { using type = T; }; -template struct unwrap_recursive> { using type = T; }; -template using unwrap_recursive_t = unwrap_recursive::type; +template +using unwrap_recursive_type = detail::unwrap_recursive_type_impl::type; + +inline constexpr detail::unwrap_recursive_fn unwrap_recursive{}; template @@ -97,7 +113,7 @@ template struct variant_alternative : std::add_const> {}; template -struct variant_alternative> : pack_indexing...> +struct variant_alternative> : pack_indexing...> { static_assert(I < sizeof...(Ts)); }; diff --git a/test/rvariant/rvariant.cpp b/test/rvariant/rvariant.cpp index a1647f4..74942c7 100644 --- a/test/rvariant/rvariant.cpp +++ b/test/rvariant/rvariant.cpp @@ -1589,15 +1589,15 @@ TEST_CASE("recursive_wrapper") // not [recursive] TEST_CASE("unwrap_recursive") // not [recursive] { - STATIC_REQUIRE(std::is_same_v())), int&>); - STATIC_REQUIRE(std::is_same_v())), int&&>); - STATIC_REQUIRE(std::is_same_v())), int const&>); - STATIC_REQUIRE(std::is_same_v())), int const&&>); - - STATIC_REQUIRE(std::is_same_v&>())), int&>); - STATIC_REQUIRE(std::is_same_v&&>())), int&&>); - STATIC_REQUIRE(std::is_same_v const&>())), int const&>); - STATIC_REQUIRE(std::is_same_v const&&>())), int const&&>); + STATIC_REQUIRE(std::is_same_v())), int&>); + STATIC_REQUIRE(std::is_same_v())), int&&>); + STATIC_REQUIRE(std::is_same_v())), int const&>); + STATIC_REQUIRE(std::is_same_v())), int const&&>); + + STATIC_REQUIRE(std::is_same_v&>())), int&>); + STATIC_REQUIRE(std::is_same_v&&>())), int&&>); + STATIC_REQUIRE(std::is_same_v const&>())), int const&>); + STATIC_REQUIRE(std::is_same_v const&&>())), int const&&>); } TEST_CASE("maybe_wrapped") // not [recursive]