Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 0 additions & 263 deletions source/meta.tex
Original file line number Diff line number Diff line change
Expand Up @@ -205,22 +205,6 @@
using @\libglobal{true_type}@ = bool_constant<true>;
using @\libglobal{false_type}@ = bool_constant<false>;

// \ref{const.wrap.class}, class template \tcode{constant_wrapper}
template<class T>
struct @\exposidnc{cw-fixed-value}@; // \expos

template<@\exposidnc{cw-fixed-value}@ X, class = typename decltype(X)::@\exposid{type}@>
struct constant_wrapper;

template<class T>
concept @\defexposconceptnc{constexpr-param}@ = // \expos
requires { typename constant_wrapper<T::value>; };

struct @\exposidnc{cw-operators}@; // \expos

template<@\exposid{cw-fixed-value}@ X>
constexpr auto @\libglobal{cw}@ = constant_wrapper<X>{};

// \ref{meta.unary.cat}, primary type categories
template<class T> struct is_void;
template<class T> struct is_null_pointer;
Expand Down Expand Up @@ -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<class T>
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<class T, size_t Extent>
struct @\exposidnc{cw-fixed-value}@<T[Extent]> { // \expos
using @\exposidnc{type}@ = T[Extent]; // \expos
constexpr @\exposidnc{cw-fixed-value}@(T (&arr)[Extent]) noexcept;
T @\exposidnc{data}@[Extent]; // \expos
};

template<class T, size_t Extent>
@\exposidnc{cw-fixed-value}@(T (&)[Extent]) -> @\exposidnc{cw-fixed-value}@<T[Extent]>; // \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<bool, decltype(L::value)> ||
!is_constructible_v<bool, decltype(R::value)>)
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<bool, decltype(L::value)> ||
!is_constructible_v<bool, decltype(R::value)>)
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<L::value->*(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<T::value(Args::value...)>(); }
{ return constant_wrapper<T::value(Args::value...)>{}; }
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}
Expand Down
2 changes: 1 addition & 1 deletion source/support.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
Loading
Loading