diff --git a/source/meta.tex b/source/meta.tex index 80182175ef..34ce37bb46 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -205,22 +205,6 @@ using @\libglobal{true_type}@ = bool_constant; using @\libglobal{false_type}@ = bool_constant; - // \ref{const.wrap.class}, class template \tcode{constant_wrapper} - template - struct @\exposidnc{cw-fixed-value}@; // \expos - - template<@\exposidnc{cw-fixed-value}@ X, class = typename decltype(X)::@\exposid{type}@> - struct constant_wrapper; - - template - concept @\defexposconceptnc{constexpr-param}@ = // \expos - requires { typename constant_wrapper; }; - - struct @\exposidnc{cw-operators}@; // \expos - - template<@\exposid{cw-fixed-value}@ X> - constexpr auto @\libglobal{cw}@ = constant_wrapper{}; - // \ref{meta.unary.cat}, primary type categories template struct is_void; template struct is_null_pointer; @@ -676,253 +660,6 @@ are used as base classes to define the interface for various type traits. -\rSec2[const.wrap.class]{Class template \tcode{constant_wrapper}} - -\begin{codeblock} -namespace std { - template - struct @\exposidnc{cw-fixed-value}@ { // \expos - using @\exposidnc{type}@ = T; // \expos - constexpr @\exposidnc{cw-fixed-value}@(@\exposidnc{type}@ v) noexcept : @\exposidnc{data}@(v) {} - T @\exposidnc{data}@; // \expos - }; - - template - struct @\exposidnc{cw-fixed-value}@ { // \expos - using @\exposidnc{type}@ = T[Extent]; // \expos - constexpr @\exposidnc{cw-fixed-value}@(T (&arr)[Extent]) noexcept; - T @\exposidnc{data}@[Extent]; // \expos - }; - - template - @\exposidnc{cw-fixed-value}@(T (&)[Extent]) -> @\exposidnc{cw-fixed-value}@; // \expos - - struct @\exposidnc{cw-operators}@ { // \expos - // unary operators - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> - { return {}; } - - // binary operators - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)> - { return {}; } - - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)> - { return {}; } - - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - requires (!is_constructible_v || - !is_constructible_v) - friend constexpr auto operator&&(L, R) noexcept - -> constant_wrapper<(L::value && R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - requires (!is_constructible_v || - !is_constructible_v) - friend constexpr auto operator||(L, R) noexcept - -> constant_wrapper<(L::value || R::value)> - { return {}; } - - // comparisons - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator<=>(L, R) noexcept - -> constant_wrapper<(L::value <=> R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)> - { return {}; } - - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator,(L, R) noexcept = delete; - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper*(R::value)> - { return {}; } - - // call and index - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@... Args> - constexpr auto operator()(this T, Args...) noexcept - requires requires { constant_wrapper(); } - { return constant_wrapper{}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@... Args> - constexpr auto operator[](this T, Args...) noexcept - -> constant_wrapper<(T::value[Args::value...])> - { return {}; } - - // pseudo-mutators - template<@\exposconcept{constexpr-param}@ T> - constexpr auto operator++(this T) noexcept - -> constant_wrapper<(++T::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T> - constexpr auto operator++(this T, int) noexcept - -> constant_wrapper<(T::value++)> { return {}; } - template<@\exposconcept{constexpr-param}@ T> - constexpr auto operator--(this T) noexcept - -> constant_wrapper<(--T::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T> - constexpr auto operator--(this T, int) noexcept - -> constant_wrapper<(T::value--)> { return {}; } - - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator+=(this T, R) noexcept - -> constant_wrapper<(T::value += R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator-=(this T, R) noexcept - -> constant_wrapper<(T::value -= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator*=(this T, R) noexcept - -> constant_wrapper<(T::value *= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator/=(this T, R) noexcept - -> constant_wrapper<(T::value /= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator%=(this T, R) noexcept - -> constant_wrapper<(T::value %= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator&=(this T, R) noexcept - -> constant_wrapper<(T::value &= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator|=(this T, R) noexcept - -> constant_wrapper<(T::value |= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator^=(this T, R) noexcept - -> constant_wrapper<(T::value ^= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator<<=(this T, R) noexcept - -> constant_wrapper<(T::value <<= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator>>=(this T, R) noexcept - -> constant_wrapper<(T::value >>= R::value)> { return {}; } - }; - - template<@\exposid{cw-fixed-value}@ X, class> - struct @\libglobal{constant_wrapper}@ : @\exposid{cw-operators}@ { - static constexpr const auto & value = X.@\exposid{data}@; - using type = constant_wrapper; - using value_type = decltype(X)::@\exposid{type}@; - - template<@\exposconcept{constexpr-param}@ R> - constexpr auto operator=(R) const noexcept - -> constant_wrapper<(value = R::value)> { return {}; } - - constexpr operator decltype(value)() const noexcept { return value; } - }; -} -\end{codeblock} - -\pnum -The class template \tcode{constant_wrapper} aids in metaprogramming by ensuring -that the evaluation of expressions comprised entirely of \tcode{constant_wrapper} -are core constant expressions\iref{expr.const.core}, -regardless of the context in which they appear. -In particular, this enables use of \tcode{constant_wrapper} values -that are passed as arguments to constexpr functions to be used in constant expressions. - -\pnum -\begin{note} -The unnamed second template parameter to \tcode{constant_wrapper} is present -to aid argument-dependent lookup\iref{basic.lookup.argdep} -in finding overloads for which \tcode{constant_wrapper}'s wrapped value is a suitable argument, -but for which the \tcode{constant_wrapper} itself is not. -\end{note} - -\pnum -\begin{example} -\begin{codeblock} - constexpr auto initial_phase(auto quantity_1, auto quantity_2) { - return quantity_1 + quantity_2; - } - - constexpr auto middle_phase(auto tbd) { - return tbd; - } - - void final_phase(auto gathered, auto available) { - if constexpr (gathered == available) - std::cout << "Profit!\n"; - } - - void impeccable_underground_planning() { - auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>)); - static_assert(gathered_quantity == 55); - auto all_available = std::cw<55>; - final_phase(gathered_quantity, all_available); - } - - void deeply_flawed_underground_planning() { - constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13)); - constexpr auto all_available = 55; - final_phase(gathered_quantity, all_available); // error: \tcode{gathered == available} - // is not a constant expression - } -\end{codeblock} -\end{example} - -\begin{itemdecl} -constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initialize elements of \exposid{data} with corresponding elements of \tcode{arr}. -\end{itemdescr} - \rSec2[meta.unary]{Unary type traits} \rSec3[meta.unary.general]{General} diff --git a/source/support.tex b/source/support.tex index 535f4bef33..180f5b58dc 100644 --- a/source/support.tex +++ b/source/support.tex @@ -620,7 +620,7 @@ #define @\defnlibxname{cpp_lib_complex_udls}@ 201309L // also in \libheader{complex} #define @\defnlibxname{cpp_lib_concepts}@ 202207L // freestanding, also in \libheader{concepts}, \libheader{compare} -#define @\defnlibxname{cpp_lib_constant_wrapper}@ 202506L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_constant_wrapper}@ 202603L // freestanding, also in \libheader{utility} #define @\defnlibxname{cpp_lib_constexpr_algorithms}@ 202306L // also in \libheader{algorithm}, \libheader{utility} #define @\defnlibxname{cpp_lib_constexpr_atomic}@ 202411L // also in \libheader{atomic} #define @\defnlibxname{cpp_lib_constexpr_bitset}@ 202207L // also in \libheader{bitset} diff --git a/source/utilities.tex b/source/utilities.tex index 66b30a91a9..db5a8591a9 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -97,6 +97,22 @@ [[noreturn]] void unreachable(); void observable_checkpoint() noexcept; + // \ref{const.wrap.class}, class template \tcode{constant_wrapper} + template + struct @\exposidnc{cw-fixed-value}@; // \expos + + template<@\exposidnc{cw-fixed-value}@ X, class = typename decltype(X)::@\exposid{type}@> + struct constant_wrapper; + + template + concept @\defexposconceptnc{constexpr-param}@ = // \expos + requires { typename constant_wrapper; }; + + struct @\exposidnc{cw-operators}@; // \expos + + template<@\exposid{cw-fixed-value}@ X> + constexpr auto @\libglobal{cw}@ = constant_wrapper{}; + // \ref{intseq}, compile-time integer sequences% \indexlibraryglobal{index_sequence}% \indexlibraryglobal{make_index_sequence}% @@ -734,6 +750,302 @@ Establishes an observable checkpoint\iref{intro.abstract}. \end{itemdescr} +\rSec2[const.wrap.class]{Class template \tcode{constant_wrapper}} + +\begin{codeblock} +namespace std { + template + struct @\exposidnc{cw-fixed-value}@ { // \expos + using @\exposidnc{type}@ = T; // \expos + constexpr @\exposidnc{cw-fixed-value}@(@\exposidnc{type}@ v) noexcept : @\exposidnc{data}@(v) {} + T @\exposidnc{data}@; // \expos + }; + + template + struct @\exposidnc{cw-fixed-value}@ { // \expos + using @\exposidnc{type}@ = T[Extent]; // \expos + constexpr @\exposidnc{cw-fixed-value}@(T (&arr)[Extent]) noexcept; + T @\exposidnc{data}@[Extent]; // \expos + }; + + template + @\exposidnc{cw-fixed-value}@(T (&)[Extent]) -> @\exposidnc{cw-fixed-value}@; // \expos + + struct @\exposidnc{cw-operators}@ { // \expos + // unary operators + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> + { return {}; } + + // binary operators + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)> + { return {}; } + + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)> + { return {}; } + + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + requires (!is_constructible_v || + !is_constructible_v) + friend constexpr auto operator&&(L, R) noexcept + -> constant_wrapper<(L::value && R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + requires (!is_constructible_v || + !is_constructible_v) + friend constexpr auto operator||(L, R) noexcept + -> constant_wrapper<(L::value || R::value)> + { return {}; } + + // comparisons + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator<=>(L, R) noexcept + -> constant_wrapper<(L::value <=> R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)> + { return {}; } + + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator,(L, R) noexcept = delete; + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper*(R::value)> + { return {}; } + + // pseudo-mutators + template<@\exposconcept{constexpr-param}@ T> + constexpr auto operator++(this T) noexcept + -> constant_wrapper<(++T::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T> + constexpr auto operator++(this T, int) noexcept + -> constant_wrapper<(T::value++)> { return {}; } + template<@\exposconcept{constexpr-param}@ T> + constexpr auto operator--(this T) noexcept + -> constant_wrapper<(--T::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T> + constexpr auto operator--(this T, int) noexcept + -> constant_wrapper<(T::value--)> { return {}; } + + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator+=(this T, R) noexcept + -> constant_wrapper<(T::value += R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator-=(this T, R) noexcept + -> constant_wrapper<(T::value -= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator*=(this T, R) noexcept + -> constant_wrapper<(T::value *= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator/=(this T, R) noexcept + -> constant_wrapper<(T::value /= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator%=(this T, R) noexcept + -> constant_wrapper<(T::value %= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator&=(this T, R) noexcept + -> constant_wrapper<(T::value &= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator|=(this T, R) noexcept + -> constant_wrapper<(T::value |= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator^=(this T, R) noexcept + -> constant_wrapper<(T::value ^= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator<<=(this T, R) noexcept + -> constant_wrapper<(T::value <<= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator>>=(this T, R) noexcept + -> constant_wrapper<(T::value >>= R::value)> { return {}; } + }; + + template<@\exposid{cw-fixed-value}@ X, class> + struct @\libglobal{constant_wrapper}@ : @\exposid{cw-operators}@ { + static constexpr const auto & value = X.@\exposid{data}@; + using type = constant_wrapper; + using value_type = decltype(X)::@\exposid{type}@; + + template<@\exposconcept{constexpr-param}@ R> + constexpr auto operator=(R) const noexcept + -> constant_wrapper<(value = R::value)> { return {}; } + + constexpr operator decltype(value)() const noexcept { return value; } + + template + static constexpr decltype(auto) operator()(Args&&... args) noexcept(@\seebelow@); + template + static constexpr decltype(auto) operator[](Args&&... args) noexcept(@\seebelow@); + }; +} +\end{codeblock} + +\pnum +The class template \tcode{constant_wrapper} aids in metaprogramming by ensuring +that the evaluation of expressions comprised entirely of \tcode{constant_wrapper} +are core constant expressions\iref{expr.const.core}, +regardless of the context in which they appear. +In particular, this enables use of \tcode{constant_wrapper} values +that are passed as arguments to constexpr functions to be used in constant expressions. + +\pnum +\begin{note} +The unnamed second template parameter to \tcode{constant_wrapper} is present +to aid argument-dependent lookup\iref{basic.lookup.argdep} +in finding overloads for which \tcode{constant_wrapper}'s wrapped value is a suitable argument, +but for which the \tcode{constant_wrapper} itself is not. +\end{note} + +\pnum +\begin{example} +\begin{codeblock} + constexpr auto initial_phase(auto quantity_1, auto quantity_2) { + return quantity_1 + quantity_2; + } + + constexpr auto middle_phase(auto tbd) { + return tbd; + } + + void final_phase(auto gathered, auto available) { + if constexpr (gathered == available) + std::cout << "Profit!\n"; + } + + void impeccable_underground_planning() { + auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>)); + static_assert(gathered_quantity == 55); + auto all_available = std::cw<55>; + final_phase(gathered_quantity, all_available); + } + + void deeply_flawed_underground_planning() { + constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13)); + constexpr auto all_available = 55; + final_phase(gathered_quantity, all_available); // error: \tcode{gathered == available} + // is not a constant expression + } +\end{codeblock} +\end{example} + +\begin{itemdecl} +constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initialize elements of \exposid{data} with corresponding elements of \tcode{arr}. +\end{itemdescr} + +\indexlibrarymember{operator()}{constant_wrapper}% +\begin{itemdecl} +template + static constexpr decltype(auto) operator()(Args&&... args) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{call-expr}} be +\tcode{constant_wrapper<\placeholder{INVOKE}(value, remove_cvref_t::value...)>\{\}} +if all types in \tcode{remove_cvref_t...} satisfy \exposconcept{constexpr-param} and +\tcode{constant_wrapper<\placeholder{INVOKE}(val\-ue, remove_cvref_t::value...)>} is a valid type, +otherwise let \tcode{\placeholder{call-expr}} be \tcode{\placeholder{INVOKE}(value, std::forward(args)...)}. + +\pnum +\constraints +\tcode{\placeholder{call-expr}} is a valid expression. + +\pnum +\effects +Equivalent to: \tcode{return \placeholder{call-expr};} + +\pnum +\remarks +The exception specification is equivalent to \tcode{noexcept(\placeholder{call-expr})}. +\end{itemdescr} + +\indexlibrarymember{operator[]}{constant_wrapper}% +\begin{itemdecl} +template + static constexpr decltype(auto) operator[](Args&&... args) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{subscr-expr}} be +\tcode{constant_wrapper::value...]>\{\}} +if all types in \tcode{remove_cvref_t...} satisfy \exposconcept{constexpr-param} and +\tcode{constant_wrapper::value...]>} is a valid type, +otherwise let \tcode{\placeholder{subscr-expr}} be \tcode{value[std::forward(args)...]}. + +\pnum +\constraints +\tcode{\placeholder{subscr-expr}} is a valid expression. + +\pnum +\effects +Equivalent to: \tcode{return \placeholder{subscr-expr};} + +\pnum +\remarks +The exception specification is equivalent to \tcode{noexcept(\placeholder{subscr-expr})}. +\end{itemdescr} + \rSec1[pairs]{Pairs} \rSec2[pairs.general]{General}