From b3d2ecad9d86030a3b3f47286c28c69e9796abb1 Mon Sep 17 00:00:00 2001 From: Alisdair Meredith Date: Wed, 25 Jun 2025 16:00:17 -0400 Subject: [PATCH 1/2] P2781R9 std::constant_wrapper Fixes 7969 Fixes cplusplus/papers#1458 Allowed paragraphs to number themselves correctly. For consistency, did not use code font for constexpr in the phrase constexpr function. This revision has many Overfull hboxes that will be addressed next commit. --- source/meta.tex | 229 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) diff --git a/source/meta.tex b/source/meta.tex index cb8e6e7ade..ea8a9502b6 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -164,6 +164,20 @@ using @\libglobal{true_type}@ = bool_constant; using @\libglobal{false_type}@ = bool_constant; + template + struct @\exposid{cw-fixed-value}@; // \expos + + template<@\exposid{cw-fixed-value}@ X, class = typename decltype(@\exposid{cw-fixed-value}@(X))::type> + struct constant_wrapper; + + template + concept @\exposid{constexpr-param}@ = requires { typename constant_wrapper; }; // \expos + + struct @\exposid{cw-operators}@; // \expos + + template<@\exposid{cw-fixed-value}@ X> + constexpr auto cw = constant_wrapper{}; + // \ref{meta.unary.cat}, primary type categories template struct is_void; template struct is_null_pointer; @@ -624,6 +638,221 @@ are used as base classes to define the interface for various type traits. +\indexlibrarymember{value_type}{integral_constant}% +\rSec2[const.wrap.class]{Class template \tcode{constant_wrapper}} + +\begin{codeblock} +template +struct @\exposid{cw-fixed-value}@ { // \expos + using type = T; // \expos + constexpr @\exposid{cw-fixed-value}@(type v) noexcept: data(v) { } + T data; // \expos +}; + +template +struct @\exposid{cw-fixed-value}@ { // \expos + using type = T[Extent]; // \expos + constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept; + T data[Extent]; // \expos +}; + +template + cw-fixed-value(T (&)[Extent]) -> cw-fixed-value; // \expos + +struct @\exposid{cw-operators}@ { // \expos + // unary operators + template<@\exposid{constexpr-param}@ T> + friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> { return {}; } + template<@\exposid{constexpr-param}@ T> + friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> { return {}; } + template<@\exposid{constexpr-param}@ T> + friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> { return {}; } + template<@\exposid{constexpr-param}@ T> + friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> { return {}; } + template<@\exposid{constexpr-param}@ T> + friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> { return {}; } + template<@\exposid{constexpr-param}@ T> + friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> { return {}; } + + // binary operators + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)> { return {}; } + + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)> { return {}; } + + template<@\exposid{constexpr-param}@ L, @\exposid{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<@\exposid{constexpr-param}@ L, @\exposid{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<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator<=>(L, R) noexcept -> constant_wrapper<(L::value <=> R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)> { return {}; } + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)> { return {}; } + + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator,(L, R) noexcept = delete; + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> + friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper*(R::value)> + { return {}; } + + // call and index + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@... Args> + constexpr auto operator()(this T, Args...) noexcept + requires requires(Args...) { constant_wrapper(); } + { return constant_wrapper{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@... Args> + constexpr auto operator[](this T, Args...) noexcept -> constant_wrapper<(T::value[Args::value...])> + { return {}; } + + // pseudo-mutators + template<@\exposid{constexpr-param}@ T> + constexpr auto operator++(this T) noexcept requires requires(T::value_type x) { ++x; } + { return constant_wrapper<[] { auto c = T::value; return ++c; }()>{}; } + template<@\exposid{constexpr-param}@ T> + constexpr auto operator++(this T, int) noexcept requires requires(T::value_type x) { x++; } + { return constant_wrapper<[] { auto c = T::value; return c++; }()>{}; } + + template<@\exposid{constexpr-param}@ T> + constexpr auto operator--(this T) noexcept requires requires(T::value_type x) { --x; } + { return constant_wrapper<[] { auto c = T::value; return --c; }()>{}; } + template<@\exposid{constexpr-param}@ T> + constexpr auto operator--(this T, int) noexcept requires requires(T::value_type x) { x--; } + { return constant_wrapper<[] { auto c = T::value; return c--; }()>{}; } + + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator+=(this T, R) noexcept requires requires(T::value_type x) { x += R::value; } + { return constant_wrapper<[] { auto v = T::value; return v += R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator-=(this T, R) noexcept requires requires(T::value_type x) { x -= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v -= R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator*=(this T, R) noexcept requires requires(T::value_type x) { x *= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v *= R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator/=(this T, R) noexcept requires requires(T::value_type x) { x /= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v /= R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator%=(this T, R) noexcept requires requires(T::value_type x) { x %= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v %= R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator&=(this T, R) noexcept requires requires(T::value_type x) { x &= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v &= R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator|=(this T, R) noexcept requires requires(T::value_type x) { x |= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v |= R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator^=(this T, R) noexcept requires requires(T::value_type x) { x ^= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v ^= R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator<<=(this T, R) noexcept requires requires(T::value_type x) { x <<= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v <<= R::value; }()>{}; } + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> + constexpr auto operator>>=(this T, R) noexcept requires requires(T::value_type x) { x >>= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v >>= R::value; }()>{}; } +}; + +template +struct constant_wrapper: cw-operators { + static constexpr const auto & value = X.data; + using type = constant_wrapper; + using value_type = typename decltype(X)::type; + + template<@\exposid{constexpr-param}@ R> + constexpr auto operator=(R) const noexcept requires requires(value_type x) { x = R::value; } + { return constant_wrapper<[] { auto v = value; return v = R::value; }()>{}; } + + constexpr operator decltype(auto)() 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}, +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: `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 \tcode{data} with corresponding elements of \tcode{arr}. +\end{itemdescr} + \rSec2[meta.unary]{Unary type traits} \rSec3[meta.unary.general]{General} From f069a820fae967f9ba3cd94fe2b3dd3f79848ed5 Mon Sep 17 00:00:00 2001 From: Alisdair Meredith Date: Wed, 25 Jun 2025 17:02:29 -0400 Subject: [PATCH 2/2] [const.wrap.class] Extensive line breaking to fit properly on the page --- source/meta.tex | 168 ++++++++++++++++++++++++++++++------------------ 1 file changed, 106 insertions(+), 62 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index ea8a9502b6..58671c96a9 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -657,68 +657,95 @@ }; template - cw-fixed-value(T (&)[Extent]) -> cw-fixed-value; // \expos + @\exposid{cw-fixed-value}@(T (&)[Extent]) -> cw-fixed-value; // \expos struct @\exposid{cw-operators}@ { // \expos // unary operators template<@\exposid{constexpr-param}@ T> - friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> { return {}; } + friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> + { return {}; } template<@\exposid{constexpr-param}@ T> - friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> { return {}; } + friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> + { return {}; } template<@\exposid{constexpr-param}@ T> - friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> { return {}; } + friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> + { return {}; } template<@\exposid{constexpr-param}@ T> - friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> { return {}; } + friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> + { return {}; } template<@\exposid{constexpr-param}@ T> - friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> { return {}; } + friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> + { return {}; } template<@\exposid{constexpr-param}@ T> - friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> { return {}; } + friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> + { return {}; } // binary operators template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)> { return {}; } + friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)> { return {}; } + friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)> { return {}; } + friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)> { return {}; } + friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)> { return {}; } + friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)> { return {}; } + friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)> { return {}; } + friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)> { return {}; } + friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)> { return {}; } + friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)> { return {}; } + friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - requires (!is_constructible_v || !is_constructible_v) - friend constexpr auto operator&&(L, R) noexcept -> constant_wrapper<(L::value && R::value)> { return {}; } + requires (!is_constructible_v || + !is_constructible_v) + friend constexpr auto operator&&(L, R) noexcept -> constant_wrapper<(L::value && R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - requires (!is_constructible_v || !is_constructible_v) - friend constexpr auto operator||(L, R) noexcept -> constant_wrapper<(L::value || R::value)> { return {}; } + requires (!is_constructible_v || + !is_constructible_v) + friend constexpr auto operator||(L, R) noexcept -> constant_wrapper<(L::value || R::value)> + { return {}; } // comparisons template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator<=>(L, R) noexcept -> constant_wrapper<(L::value <=> R::value)> { return {}; } + friend constexpr auto operator<=>(L, R) noexcept -> constant_wrapper<(L::value <=> R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)> { return {}; } + friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)> { return {}; } + friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)> { return {}; } + friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)> { return {}; } + friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)> { return {}; } + friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> - friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)> { return {}; } + friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)> + { return {}; } template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> friend constexpr auto operator,(L, R) noexcept = delete; @@ -732,65 +759,81 @@ requires requires(Args...) { constant_wrapper(); } { return constant_wrapper{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@... Args> - constexpr auto operator[](this T, Args...) noexcept -> constant_wrapper<(T::value[Args::value...])> - { return {}; } + constexpr auto operator[](this T, Args...) noexcept + -> constant_wrapper<(T::value[Args::value...])> + { return {}; } // pseudo-mutators template<@\exposid{constexpr-param}@ T> - constexpr auto operator++(this T) noexcept requires requires(T::value_type x) { ++x; } - { return constant_wrapper<[] { auto c = T::value; return ++c; }()>{}; } + constexpr auto operator++(this T) noexcept + requires requires(T::value_type x) { ++x; } + { return constant_wrapper<[] { auto c = T::value; return ++c; }()>{}; } template<@\exposid{constexpr-param}@ T> - constexpr auto operator++(this T, int) noexcept requires requires(T::value_type x) { x++; } - { return constant_wrapper<[] { auto c = T::value; return c++; }()>{}; } + constexpr auto operator++(this T, int) noexcept + requires requires(T::value_type x) { x++; } + { return constant_wrapper<[] { auto c = T::value; return c++; }()>{}; } template<@\exposid{constexpr-param}@ T> - constexpr auto operator--(this T) noexcept requires requires(T::value_type x) { --x; } - { return constant_wrapper<[] { auto c = T::value; return --c; }()>{}; } + constexpr auto operator--(this T) noexcept + requires requires(T::value_type x) { --x; } + { return constant_wrapper<[] { auto c = T::value; return --c; }()>{}; } template<@\exposid{constexpr-param}@ T> - constexpr auto operator--(this T, int) noexcept requires requires(T::value_type x) { x--; } - { return constant_wrapper<[] { auto c = T::value; return c--; }()>{}; } + constexpr auto operator--(this T, int) noexcept + requires requires(T::value_type x) { x--; } + { return constant_wrapper<[] { auto c = T::value; return c--; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator+=(this T, R) noexcept requires requires(T::value_type x) { x += R::value; } - { return constant_wrapper<[] { auto v = T::value; return v += R::value; }()>{}; } + constexpr auto operator+=(this T, R) noexcept + requires requires(T::value_type x) { x += R::value; } + { return constant_wrapper<[] { auto v = T::value; return v += R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator-=(this T, R) noexcept requires requires(T::value_type x) { x -= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v -= R::value; }()>{}; } + constexpr auto operator-=(this T, R) noexcept + requires requires(T::value_type x) { x -= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v -= R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator*=(this T, R) noexcept requires requires(T::value_type x) { x *= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v *= R::value; }()>{}; } + constexpr auto operator*=(this T, R) noexcept + requires requires(T::value_type x) { x *= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v *= R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator/=(this T, R) noexcept requires requires(T::value_type x) { x /= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v /= R::value; }()>{}; } + constexpr auto operator/=(this T, R) noexcept + requires requires(T::value_type x) { x /= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v /= R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator%=(this T, R) noexcept requires requires(T::value_type x) { x %= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v %= R::value; }()>{}; } + constexpr auto operator%=(this T, R) noexcept + requires requires(T::value_type x) { x %= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v %= R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator&=(this T, R) noexcept requires requires(T::value_type x) { x &= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v &= R::value; }()>{}; } + constexpr auto operator&=(this T, R) noexcept + requires requires(T::value_type x) { x &= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v &= R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator|=(this T, R) noexcept requires requires(T::value_type x) { x |= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v |= R::value; }()>{}; } + constexpr auto operator|=(this T, R) noexcept + requires requires(T::value_type x) { x |= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v |= R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator^=(this T, R) noexcept requires requires(T::value_type x) { x ^= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v ^= R::value; }()>{}; } + constexpr auto operator^=(this T, R) noexcept + requires requires(T::value_type x) { x ^= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v ^= R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator<<=(this T, R) noexcept requires requires(T::value_type x) { x <<= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v <<= R::value; }()>{}; } + constexpr auto operator<<=(this T, R) noexcept + requires requires(T::value_type x) { x <<= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v <<= R::value; }()>{}; } template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> - constexpr auto operator>>=(this T, R) noexcept requires requires(T::value_type x) { x >>= R::value; } - { return constant_wrapper<[] { auto v = T::value; return v >>= R::value; }()>{}; } + constexpr auto operator>>=(this T, R) noexcept + requires requires(T::value_type x) { x >>= R::value; } + { return constant_wrapper<[] { auto v = T::value; return v >>= R::value; }()>{}; } }; -template +template<@\exposid{cw-fixed-value}@ X, class> struct constant_wrapper: cw-operators { static constexpr const auto & value = X.data; using type = constant_wrapper; using value_type = typename decltype(X)::type; template<@\exposid{constexpr-param}@ R> - constexpr auto operator=(R) const noexcept requires requires(value_type x) { x = R::value; } - { return constant_wrapper<[] { auto v = value; return v = R::value; }()>{}; } + constexpr auto operator=(R) const noexcept + requires requires(value_type x) { x = R::value; } + { return constant_wrapper<[] { auto v = value; return v = R::value; }()>{}; } constexpr operator decltype(auto)() const noexcept { return value; } }; @@ -838,7 +881,8 @@ 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: `gathered == available' is not a constant expression + final_phase(gathered_quantity, all_available); // error: + // `gathered == available' is not a constant expression } \end{codeblock} \end{example}