-
Notifications
You must be signed in to change notification settings - Fork 777
P2781R9 std::constant_wrapper #8018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -164,6 +164,20 @@ | |||||||||||||
using @\libglobal{true_type}@ = bool_constant<true>; | ||||||||||||||
using @\libglobal{false_type}@ = bool_constant<false>; | ||||||||||||||
|
||||||||||||||
template<class T> | ||||||||||||||
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<class T> | ||||||||||||||
concept @\exposid{constexpr-param}@ = requires { typename constant_wrapper<T::value>; }; // \expos | ||||||||||||||
|
||||||||||||||
struct @\exposid{cw-operators}@; // \expos | ||||||||||||||
|
||||||||||||||
template<@\exposid{cw-fixed-value}@ X> | ||||||||||||||
constexpr auto cw = constant_wrapper<X>{}; | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
… I think. I'm still new to indexing, myself. 😉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a missing @ at the end of libglobal{cw}. Otherwise agreed with the approach. |
||||||||||||||
|
||||||||||||||
// \ref{meta.unary.cat}, primary type categories | ||||||||||||||
template<class T> struct is_void; | ||||||||||||||
template<class T> struct is_null_pointer; | ||||||||||||||
|
@@ -624,6 +638,265 @@ | |||||||||||||
are used as base classes to define | ||||||||||||||
the interface for various type traits. | ||||||||||||||
|
||||||||||||||
\indexlibrarymember{value_type}{integral_constant}% | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line seems to be a copy&paste left-over? |
||||||||||||||
\rSec2[const.wrap.class]{Class template \tcode{constant_wrapper}} | ||||||||||||||
|
||||||||||||||
\begin{codeblock} | ||||||||||||||
template<class T> | ||||||||||||||
struct @\exposid{cw-fixed-value}@ { // \expos | ||||||||||||||
using type = T; // \expos | ||||||||||||||
constexpr @\exposid{cw-fixed-value}@(type v) noexcept: data(v) { } | ||||||||||||||
T data; // \expos | ||||||||||||||
Comment on lines
+647
to
+649
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
At least, that's what I recall from review in LWG. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both are marked with "// \expos", so should use \exposid decoration, yes. (Also all uses of these identifiers.) |
||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
template<class T, size_t Extent> | ||||||||||||||
struct @\exposid{cw-fixed-value}@<T[Extent]> { // \expos | ||||||||||||||
using type = T[Extent]; // \expos | ||||||||||||||
constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept; | ||||||||||||||
T data[Extent]; // \expos | ||||||||||||||
Comment on lines
+654
to
+656
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise. |
||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
template<class T, size_t Extent> | ||||||||||||||
@\exposid{cw-fixed-value}@(T (&)[Extent]) -> cw-fixed-value<T[Extent]>; // \expos | ||||||||||||||
|
||||||||||||||
struct @\exposid{cw-operators}@ { // \expos | ||||||||||||||
// unary operators | ||||||||||||||
template<@\exposid{constexpr-param}@ T> | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Forgot this one before. Same for all the other uses of constexpr-param |
||||||||||||||
friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Same for all the other operators. Though, |
||||||||||||||
{ 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<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<@\exposid{constexpr-param}@ L, @\exposid{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<@\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<L::value->*(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<T::value(Args::value...)>(); } | ||||||||||||||
{ return constant_wrapper<T::value(Args::value...)>{}; } | ||||||||||||||
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<@\exposid{cw-fixed-value}@ X, class> | ||||||||||||||
struct constant_wrapper: cw-operators { | ||||||||||||||
static constexpr const auto & value = X.data; | ||||||||||||||
using type = constant_wrapper; | ||||||||||||||
Comment on lines
+828
to
+830
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... and make "data" \exposid, assuming it's the exposition-only thing from earlier. |
||||||||||||||
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}. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
\end{itemdescr} | ||||||||||||||
|
||||||||||||||
\rSec2[meta.unary]{Unary type traits} | ||||||||||||||
|
||||||||||||||
\rSec3[meta.unary.general]{General} | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.