Skip to content

Commit 5fd338c

Browse files
authored
Merge 2025-06 LWG Motion 32
P2781R9 std::constant_wrapper
2 parents 558a03f + 1c503b2 commit 5fd338c

File tree

3 files changed

+276
-1
lines changed

3 files changed

+276
-1
lines changed

source/containers.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20190,7 +20190,7 @@
2019020190

2019120191
template<class T>
2019220192
concept @\defexposconcept{integral-constant-like}@ = // \expos
20193-
is_integral_v<decltype(T::value)> &&
20193+
is_integral_v<remove_cv_ref_t<decltype(T::value)>> &&
2019420194
!is_same_v<bool, remove_const_t<decltype(T::value)>> &&
2019520195
@\libconcept{convertible_to}@<T, decltype(T::value)> &&
2019620196
@\libconcept{equality_comparable_with}@<T, decltype(T::value)> &&

source/meta.tex

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

168+
// \ref{const.wrap.class}, class template \tcode{constant_wrapper}
169+
template<class T>
170+
struct @\exposidnc{cw-fixed-value}@; // \expos
171+
172+
template<@\exposidnc{cw-fixed-value}@ X, class = typename decltype(@\exposid{cw-fixed-value}@(X))::@\exposid{type}@>
173+
struct constant_wrapper;
174+
175+
template<class T>
176+
concept @\defexposconceptnc{constexpr-param}@ = // \expos
177+
requires { typename constant_wrapper<T::value>; };
178+
179+
struct @\exposidnc{cw-operators}@; // \expos
180+
181+
template<@\exposid{cw-fixed-value}@ X>
182+
constexpr auto @\libglobal{cw}@ = constant_wrapper<X>{};
183+
168184
// \ref{meta.unary.cat}, primary type categories
169185
template<class T> struct is_void;
170186
template<class T> struct is_null_pointer;
@@ -631,6 +647,264 @@
631647
are used as base classes to define
632648
the interface for various type traits.
633649

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

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

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@
618618
#define @\defnlibxname{cpp_lib_complex_udls}@ 201309L // also in \libheader{complex}
619619
#define @\defnlibxname{cpp_lib_concepts}@ 202207L
620620
// freestanding, also in \libheader{concepts}, \libheader{compare}
621+
#define @\defnlibxname{cpp_lib_constant_wrapper}@ 202506L // also in \libheader{type_traits}
621622
#define @\defnlibxname{cpp_lib_constexpr_algorithms}@ 202306L // also in \libheader{algorithm}, \libheader{utility}
622623
#define @\defnlibxname{cpp_lib_constexpr_atomic}@ 202411L // also in \libheader{atomic}
623624
#define @\defnlibxname{cpp_lib_constexpr_bitset}@ 202207L // also in \libheader{bitset}

0 commit comments

Comments
 (0)