Skip to content

Commit 802203c

Browse files
AlisdairMtkoeppe
authored andcommitted
P2781R9 std::constant_wrapper
1 parent 558a03f commit 802203c

File tree

1 file changed

+273
-0
lines changed

1 file changed

+273
-0
lines changed

source/meta.tex

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,20 @@
165165
using @\libglobal{true_type}@ = bool_constant<true>;
166166
using @\libglobal{false_type}@ = bool_constant<false>;
167167

168+
template<class T>
169+
struct @\exposid{cw-fixed-value}@; // \expos
170+
171+
template<@\exposid{cw-fixed-value}@ X, class = typename decltype(@\exposid{cw-fixed-value}@(X))::type>
172+
struct constant_wrapper;
173+
174+
template<class T>
175+
concept @\exposid{constexpr-param}@ = requires { typename constant_wrapper<T::value>; }; // \expos
176+
177+
struct @\exposid{cw-operators}@; // \expos
178+
179+
template<@\exposid{cw-fixed-value}@ X>
180+
constexpr auto cw = constant_wrapper<X>{};
181+
168182
// \ref{meta.unary.cat}, primary type categories
169183
template<class T> struct is_void;
170184
template<class T> struct is_null_pointer;
@@ -631,6 +645,265 @@
631645
are used as base classes to define
632646
the interface for various type traits.
633647

648+
\indexlibrarymember{value_type}{integral_constant}%
649+
\rSec2[const.wrap.class]{Class template \tcode{constant_wrapper}}
650+
651+
\begin{codeblock}
652+
template<class T>
653+
struct @\exposid{cw-fixed-value}@ { // \expos
654+
using type = T; // \expos
655+
constexpr @\exposid{cw-fixed-value}@(type v) noexcept: data(v) { }
656+
T data; // \expos
657+
};
658+
659+
template<class T, size_t Extent>
660+
struct @\exposid{cw-fixed-value}@<T[Extent]> { // \expos
661+
using type = T[Extent]; // \expos
662+
constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept;
663+
T data[Extent]; // \expos
664+
};
665+
666+
template<class T, size_t Extent>
667+
@\exposid{cw-fixed-value}@(T (&)[Extent]) -> cw-fixed-value<T[Extent]>; // \expos
668+
669+
struct @\exposid{cw-operators}@ { // \expos
670+
// unary operators
671+
template<@\exposid{constexpr-param}@ T>
672+
friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)>
673+
{ return {}; }
674+
template<@\exposid{constexpr-param}@ T>
675+
friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)>
676+
{ return {}; }
677+
template<@\exposid{constexpr-param}@ T>
678+
friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)>
679+
{ return {}; }
680+
template<@\exposid{constexpr-param}@ T>
681+
friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)>
682+
{ return {}; }
683+
template<@\exposid{constexpr-param}@ T>
684+
friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)>
685+
{ return {}; }
686+
template<@\exposid{constexpr-param}@ T>
687+
friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)>
688+
{ return {}; }
689+
690+
// binary operators
691+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
692+
friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)>
693+
{ return {}; }
694+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
695+
friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)>
696+
{ return {}; }
697+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
698+
friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)>
699+
{ return {}; }
700+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
701+
friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)>
702+
{ return {}; }
703+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
704+
friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)>
705+
{ return {}; }
706+
707+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
708+
friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)>
709+
{ return {}; }
710+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
711+
friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)>
712+
{ return {}; }
713+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
714+
friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)>
715+
{ return {}; }
716+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
717+
friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)>
718+
{ return {}; }
719+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
720+
friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)>
721+
{ return {}; }
722+
723+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
724+
requires (!is_constructible_v<bool, decltype(L::value)> ||
725+
!is_constructible_v<bool, decltype(R::value)>)
726+
friend constexpr auto operator&&(L, R) noexcept -> constant_wrapper<(L::value && R::value)>
727+
{ return {}; }
728+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
729+
requires (!is_constructible_v<bool, decltype(L::value)> ||
730+
!is_constructible_v<bool, decltype(R::value)>)
731+
friend constexpr auto operator||(L, R) noexcept -> constant_wrapper<(L::value || R::value)>
732+
{ return {}; }
733+
734+
// comparisons
735+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
736+
friend constexpr auto operator<=>(L, R) noexcept -> constant_wrapper<(L::value <=> R::value)>
737+
{ return {}; }
738+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
739+
friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)>
740+
{ return {}; }
741+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
742+
friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)>
743+
{ return {}; }
744+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
745+
friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)>
746+
{ return {}; }
747+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
748+
friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)>
749+
{ return {}; }
750+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
751+
friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)>
752+
{ return {}; }
753+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
754+
friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)>
755+
{ return {}; }
756+
757+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
758+
friend constexpr auto operator,(L, R) noexcept = delete;
759+
template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R>
760+
friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper<L::value->*(R::value)>
761+
{ return {}; }
762+
763+
// call and index
764+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@... Args>
765+
constexpr auto operator()(this T, Args...) noexcept
766+
requires requires(Args...) { constant_wrapper<T::value(Args::value...)>(); }
767+
{ return constant_wrapper<T::value(Args::value...)>{}; }
768+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@... Args>
769+
constexpr auto operator[](this T, Args...) noexcept
770+
-> constant_wrapper<(T::value[Args::value...])>
771+
{ return {}; }
772+
773+
// pseudo-mutators
774+
template<@\exposid{constexpr-param}@ T>
775+
constexpr auto operator++(this T) noexcept
776+
requires requires(T::value_type x) { ++x; }
777+
{ return constant_wrapper<[] { auto c = T::value; return ++c; }()>{}; }
778+
template<@\exposid{constexpr-param}@ T>
779+
constexpr auto operator++(this T, int) noexcept
780+
requires requires(T::value_type x) { x++; }
781+
{ return constant_wrapper<[] { auto c = T::value; return c++; }()>{}; }
782+
783+
template<@\exposid{constexpr-param}@ T>
784+
constexpr auto operator--(this T) noexcept
785+
requires requires(T::value_type x) { --x; }
786+
{ return constant_wrapper<[] { auto c = T::value; return --c; }()>{}; }
787+
template<@\exposid{constexpr-param}@ T>
788+
constexpr auto operator--(this T, int) noexcept
789+
requires requires(T::value_type x) { x--; }
790+
{ return constant_wrapper<[] { auto c = T::value; return c--; }()>{}; }
791+
792+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
793+
constexpr auto operator+=(this T, R) noexcept
794+
requires requires(T::value_type x) { x += R::value; }
795+
{ return constant_wrapper<[] { auto v = T::value; return v += R::value; }()>{}; }
796+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
797+
constexpr auto operator-=(this T, R) noexcept
798+
requires requires(T::value_type x) { x -= R::value; }
799+
{ return constant_wrapper<[] { auto v = T::value; return v -= R::value; }()>{}; }
800+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
801+
constexpr auto operator*=(this T, R) noexcept
802+
requires requires(T::value_type x) { x *= R::value; }
803+
{ return constant_wrapper<[] { auto v = T::value; return v *= R::value; }()>{}; }
804+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
805+
constexpr auto operator/=(this T, R) noexcept
806+
requires requires(T::value_type x) { x /= R::value; }
807+
{ return constant_wrapper<[] { auto v = T::value; return v /= R::value; }()>{}; }
808+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
809+
constexpr auto operator%=(this T, R) noexcept
810+
requires requires(T::value_type x) { x %= R::value; }
811+
{ return constant_wrapper<[] { auto v = T::value; return v %= R::value; }()>{}; }
812+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
813+
constexpr auto operator&=(this T, R) noexcept
814+
requires requires(T::value_type x) { x &= R::value; }
815+
{ return constant_wrapper<[] { auto v = T::value; return v &= R::value; }()>{}; }
816+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
817+
constexpr auto operator|=(this T, R) noexcept
818+
requires requires(T::value_type x) { x |= R::value; }
819+
{ return constant_wrapper<[] { auto v = T::value; return v |= R::value; }()>{}; }
820+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
821+
constexpr auto operator^=(this T, R) noexcept
822+
requires requires(T::value_type x) { x ^= R::value; }
823+
{ return constant_wrapper<[] { auto v = T::value; return v ^= R::value; }()>{}; }
824+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
825+
constexpr auto operator<<=(this T, R) noexcept
826+
requires requires(T::value_type x) { x <<= R::value; }
827+
{ return constant_wrapper<[] { auto v = T::value; return v <<= R::value; }()>{}; }
828+
template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R>
829+
constexpr auto operator>>=(this T, R) noexcept
830+
requires requires(T::value_type x) { x >>= R::value; }
831+
{ return constant_wrapper<[] { auto v = T::value; return v >>= R::value; }()>{}; }
832+
};
833+
834+
template<@\exposid{cw-fixed-value}@ X, class>
835+
struct constant_wrapper: cw-operators {
836+
static constexpr const auto & value = X.data;
837+
using type = constant_wrapper;
838+
using value_type = typename decltype(X)::type;
839+
840+
template<@\exposid{constexpr-param}@ R>
841+
constexpr auto operator=(R) const noexcept
842+
requires requires(value_type x) { x = R::value; }
843+
{ return constant_wrapper<[] { auto v = value; return v = R::value; }()>{}; }
844+
845+
constexpr operator decltype(auto)() const noexcept { return value; }
846+
};
847+
\end{codeblock}
848+
849+
\pnum
850+
The class template \tcode{constant_wrapper} aids in metaprogramming by ensuring
851+
that the evaluation of expressions comprised entirely of \tcode{constant_wrapper}
852+
are core constant expressions\iref{expr.const},
853+
regardless of the context in which they appear.
854+
In particular, this enables use of \tcode{constant_wrapper} values
855+
that are passed as arguments to constexpr functions to be used in constant expressions.
856+
857+
\pnum
858+
\begin{note}
859+
The unnamed second template parameter to \tcode{constant_wrapper} is present
860+
to aid argument-dependent lookup\iref{basic.lookup.argdep}
861+
in finding overloads for which \tcode{constant_wrapper}'s wrapped value is a suitable argument,
862+
but for which the \tcode{constant_wrapper} itself is not.
863+
\end{note}
864+
865+
\pnum
866+
\begin{example}
867+
\begin{codeblock}
868+
constexpr auto initial_phase(auto quantity_1, auto quantity_2) {
869+
return quantity_1 + quantity_2;
870+
}
871+
872+
constexpr auto middle_phase(auto tbd) {
873+
return tbd;
874+
}
875+
876+
void final_phase(auto gathered, auto available) {
877+
if constexpr (gathered == available)
878+
std::cout << "Profit!\n";
879+
}
880+
881+
void impeccable_underground_planning() {
882+
auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>));
883+
static_assert(gathered_quantity == 55);
884+
auto all_available = std::cw<55>;
885+
final_phase(gathered_quantity, all_available);
886+
}
887+
888+
void deeply_flawed_underground_planning() {
889+
constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13));
890+
constexpr auto all_available = 55;
891+
final_phase(gathered_quantity, all_available); // error:
892+
// `gathered == available' is not a constant expression
893+
}
894+
\end{codeblock}
895+
\end{example}
896+
897+
\begin{itemdecl}
898+
constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept;
899+
\end{itemdecl}
900+
901+
\begin{itemdescr}
902+
\pnum
903+
\effects
904+
Initialize elements of \tcode{data} with corresponding elements of \tcode{arr}.
905+
\end{itemdescr}
906+
634907
\rSec2[meta.unary]{Unary type traits}
635908

636909
\rSec3[meta.unary.general]{General}

0 commit comments

Comments
 (0)