|
164 | 164 | using @\libglobal{true_type}@ = bool_constant<true>; |
165 | 165 | using @\libglobal{false_type}@ = bool_constant<false>; |
166 | 166 |
|
| 167 | + template<class T> |
| 168 | + struct @\exposid{cw-fixed-value}@; // \expos |
| 169 | + |
| 170 | + template<@\exposid{cw-fixed-value}@ X, class = typename decltype(@\exposid{cw-fixed-value}@(X))::type> |
| 171 | + struct constant_wrapper; |
| 172 | + |
| 173 | + template<class T> |
| 174 | + concept @\exposid{constexpr-param}@ = requires { typename constant_wrapper<T::value>; }; // \expos |
| 175 | + |
| 176 | + struct @\exposid{cw-operators}@; // \expos |
| 177 | + |
| 178 | + template<@\exposid{cw-fixed-value}@ X> |
| 179 | + constexpr auto cw = constant_wrapper<X>{}; |
| 180 | + |
167 | 181 | // \ref{meta.unary.cat}, primary type categories |
168 | 182 | template<class T> struct is_void; |
169 | 183 | template<class T> struct is_null_pointer; |
|
624 | 638 | are used as base classes to define |
625 | 639 | the interface for various type traits. |
626 | 640 |
|
| 641 | +\indexlibrarymember{value_type}{integral_constant}% |
| 642 | +\rSec2[const.wrap.class]{Class template \tcode{constant_wrapper}} |
| 643 | + |
| 644 | +\begin{codeblock} |
| 645 | +template<class T> |
| 646 | +struct @\exposid{cw-fixed-value}@ { // \expos |
| 647 | + using type = T; // \expos |
| 648 | + constexpr @\exposid{cw-fixed-value}@(type v) noexcept: data(v) { } |
| 649 | + T data; // \expos |
| 650 | +}; |
| 651 | + |
| 652 | +template<class T, size_t Extent> |
| 653 | +struct @\exposid{cw-fixed-value}@<T[Extent]> { // \expos |
| 654 | + using type = T[Extent]; // \expos |
| 655 | + constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept; |
| 656 | + T data[Extent]; // \expos |
| 657 | +}; |
| 658 | + |
| 659 | +template<class T, size_t Extent> |
| 660 | + cw-fixed-value(T (&)[Extent]) -> cw-fixed-value<T[Extent]>; // \expos |
| 661 | + |
| 662 | +struct @\exposid{cw-operators}@ { // \expos |
| 663 | + // unary operators |
| 664 | + template<@\exposid{constexpr-param}@ T> |
| 665 | + friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> { return {}; } |
| 666 | + template<@\exposid{constexpr-param}@ T> |
| 667 | + friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> { return {}; } |
| 668 | + template<@\exposid{constexpr-param}@ T> |
| 669 | + friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> { return {}; } |
| 670 | + template<@\exposid{constexpr-param}@ T> |
| 671 | + friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> { return {}; } |
| 672 | + template<@\exposid{constexpr-param}@ T> |
| 673 | + friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> { return {}; } |
| 674 | + template<@\exposid{constexpr-param}@ T> |
| 675 | + friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> { return {}; } |
| 676 | + |
| 677 | + // binary operators |
| 678 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 679 | + friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)> { return {}; } |
| 680 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 681 | + friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)> { return {}; } |
| 682 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 683 | + friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)> { return {}; } |
| 684 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 685 | + friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)> { return {}; } |
| 686 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 687 | + friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)> { return {}; } |
| 688 | + |
| 689 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 690 | + friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)> { return {}; } |
| 691 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 692 | + friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)> { return {}; } |
| 693 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 694 | + friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)> { return {}; } |
| 695 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 696 | + friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)> { 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)> { return {}; } |
| 699 | + |
| 700 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 701 | + requires (!is_constructible_v<bool, decltype(L::value)> || !is_constructible_v<bool, decltype(R::value)>) |
| 702 | + friend constexpr auto operator&&(L, R) noexcept -> constant_wrapper<(L::value && R::value)> { return {}; } |
| 703 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 704 | + requires (!is_constructible_v<bool, decltype(L::value)> || !is_constructible_v<bool, decltype(R::value)>) |
| 705 | + friend constexpr auto operator||(L, R) noexcept -> constant_wrapper<(L::value || R::value)> { return {}; } |
| 706 | + |
| 707 | + // comparisons |
| 708 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 709 | + friend constexpr auto operator<=>(L, R) noexcept -> constant_wrapper<(L::value <=> R::value)> { 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)> { return {}; } |
| 712 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 713 | + friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)> { return {}; } |
| 714 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 715 | + friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)> { 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)> { return {}; } |
| 718 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 719 | + friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)> { return {}; } |
| 720 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 721 | + friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)> { return {}; } |
| 722 | + |
| 723 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 724 | + friend constexpr auto operator,(L, R) noexcept = delete; |
| 725 | + template<@\exposid{constexpr-param}@ L, @\exposid{constexpr-param}@ R> |
| 726 | + friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper<L::value->*(R::value)> |
| 727 | + { return {}; } |
| 728 | + |
| 729 | + // call and index |
| 730 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@... Args> |
| 731 | + constexpr auto operator()(this T, Args...) noexcept |
| 732 | + requires requires(Args...) { constant_wrapper<T::value(Args::value...)>(); } |
| 733 | + { return constant_wrapper<T::value(Args::value...)>{}; } |
| 734 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@... Args> |
| 735 | + constexpr auto operator[](this T, Args...) noexcept -> constant_wrapper<(T::value[Args::value...])> |
| 736 | + { return {}; } |
| 737 | + |
| 738 | + // pseudo-mutators |
| 739 | + template<@\exposid{constexpr-param}@ T> |
| 740 | + constexpr auto operator++(this T) noexcept requires requires(T::value_type x) { ++x; } |
| 741 | + { return constant_wrapper<[] { auto c = T::value; return ++c; }()>{}; } |
| 742 | + template<@\exposid{constexpr-param}@ T> |
| 743 | + constexpr auto operator++(this T, int) noexcept requires requires(T::value_type x) { x++; } |
| 744 | + { return constant_wrapper<[] { auto c = T::value; return c++; }()>{}; } |
| 745 | + |
| 746 | + template<@\exposid{constexpr-param}@ T> |
| 747 | + constexpr auto operator--(this T) noexcept requires requires(T::value_type x) { --x; } |
| 748 | + { return constant_wrapper<[] { auto c = T::value; return --c; }()>{}; } |
| 749 | + template<@\exposid{constexpr-param}@ T> |
| 750 | + constexpr auto operator--(this T, int) noexcept requires requires(T::value_type x) { x--; } |
| 751 | + { return constant_wrapper<[] { auto c = T::value; return c--; }()>{}; } |
| 752 | + |
| 753 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 754 | + constexpr auto operator+=(this T, R) noexcept requires requires(T::value_type x) { x += R::value; } |
| 755 | + { return constant_wrapper<[] { auto v = T::value; return v += R::value; }()>{}; } |
| 756 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 757 | + constexpr auto operator-=(this T, R) noexcept requires requires(T::value_type x) { x -= R::value; } |
| 758 | + { return constant_wrapper<[] { auto v = T::value; return v -= R::value; }()>{}; } |
| 759 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 760 | + constexpr auto operator*=(this T, R) noexcept requires requires(T::value_type x) { x *= R::value; } |
| 761 | + { return constant_wrapper<[] { auto v = T::value; return v *= R::value; }()>{}; } |
| 762 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 763 | + constexpr auto operator/=(this T, R) noexcept requires requires(T::value_type x) { x /= R::value; } |
| 764 | + { return constant_wrapper<[] { auto v = T::value; return v /= R::value; }()>{}; } |
| 765 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 766 | + constexpr auto operator%=(this T, R) noexcept requires requires(T::value_type x) { x %= R::value; } |
| 767 | + { return constant_wrapper<[] { auto v = T::value; return v %= R::value; }()>{}; } |
| 768 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 769 | + constexpr auto operator&=(this T, R) noexcept requires requires(T::value_type x) { x &= R::value; } |
| 770 | + { return constant_wrapper<[] { auto v = T::value; return v &= R::value; }()>{}; } |
| 771 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 772 | + constexpr auto operator|=(this T, R) noexcept requires requires(T::value_type x) { x |= R::value; } |
| 773 | + { return constant_wrapper<[] { auto v = T::value; return v |= R::value; }()>{}; } |
| 774 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 775 | + constexpr auto operator^=(this T, R) noexcept requires requires(T::value_type x) { x ^= R::value; } |
| 776 | + { return constant_wrapper<[] { auto v = T::value; return v ^= R::value; }()>{}; } |
| 777 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 778 | + constexpr auto operator<<=(this T, R) noexcept requires requires(T::value_type x) { x <<= R::value; } |
| 779 | + { return constant_wrapper<[] { auto v = T::value; return v <<= R::value; }()>{}; } |
| 780 | + template<@\exposid{constexpr-param}@ T, @\exposid{constexpr-param}@ R> |
| 781 | + constexpr auto operator>>=(this T, R) noexcept requires requires(T::value_type x) { x >>= R::value; } |
| 782 | + { return constant_wrapper<[] { auto v = T::value; return v >>= R::value; }()>{}; } |
| 783 | +}; |
| 784 | + |
| 785 | +template<cw-fixed-value X, class> |
| 786 | +struct constant_wrapper: cw-operators { |
| 787 | + static constexpr const auto & value = X.data; |
| 788 | + using type = constant_wrapper; |
| 789 | + using value_type = typename decltype(X)::type; |
| 790 | + |
| 791 | + template<@\exposid{constexpr-param}@ R> |
| 792 | + constexpr auto operator=(R) const noexcept requires requires(value_type x) { x = R::value; } |
| 793 | + { return constant_wrapper<[] { auto v = value; return v = R::value; }()>{}; } |
| 794 | + |
| 795 | + constexpr operator decltype(auto)() const noexcept { return value; } |
| 796 | +}; |
| 797 | +\end{codeblock} |
| 798 | + |
| 799 | +\pnum |
| 800 | +The class template \tcode{constant_wrapper} aids in metaprogramming by ensuring |
| 801 | +that the evaluation of expressions comprised entirely of \tcode{constant_wrapper} |
| 802 | +are core constant expressions\iref{expr.const}, |
| 803 | +regardless of the context in which they appear. |
| 804 | +In particular, this enables use of \tcode{constant_wrapper} values |
| 805 | +that are passed as arguments to constexpr functions to be used in constant expressions. |
| 806 | + |
| 807 | +\pnum |
| 808 | +\begin{note} |
| 809 | +The unnamed second template parameter to \tcode{constant_wrapper} is present |
| 810 | +to aid argument-dependent lookup\iref{basic.lookup.argdep} |
| 811 | +in finding overloads for which \tcode{constant_wrapper}'s wrapped value is a suitable argument, |
| 812 | +but for which the \tcode{constant_wrapper} itself is not. |
| 813 | +\end{note} |
| 814 | + |
| 815 | +\pnum |
| 816 | +\begin{example} |
| 817 | +\begin{codeblock} |
| 818 | + constexpr auto initial_phase(auto quantity_1, auto quantity_2) { |
| 819 | + return quantity_1 + quantity_2; |
| 820 | + } |
| 821 | + |
| 822 | + constexpr auto middle_phase(auto tbd) { |
| 823 | + return tbd; |
| 824 | + } |
| 825 | + |
| 826 | + void final_phase(auto gathered, auto available) { |
| 827 | + if constexpr (gathered == available) |
| 828 | + std::cout << "Profit!\n"; |
| 829 | + } |
| 830 | + |
| 831 | + void impeccable_underground_planning() { |
| 832 | + auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>)); |
| 833 | + static_assert(gathered_quantity == 55); |
| 834 | + auto all_available = std::cw<55>; |
| 835 | + final_phase(gathered_quantity, all_available); |
| 836 | + } |
| 837 | + |
| 838 | + void deeply_flawed_underground_planning() { |
| 839 | + constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13)); |
| 840 | + constexpr auto all_available = 55; |
| 841 | + final_phase(gathered_quantity, all_available); // error: `gathered == available' is not a constant expression |
| 842 | + } |
| 843 | +\end{codeblock} |
| 844 | +\end{example} |
| 845 | + |
| 846 | +\begin{itemdecl} |
| 847 | +constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept; |
| 848 | +\end{itemdecl} |
| 849 | + |
| 850 | +\begin{itemdescr} |
| 851 | +\pnum |
| 852 | +\effects |
| 853 | +Initialize elements of \tcode{data} with corresponding elements of \tcode{arr}. |
| 854 | +\end{itemdescr} |
| 855 | + |
627 | 856 | \rSec2[meta.unary]{Unary type traits} |
628 | 857 |
|
629 | 858 | \rSec3[meta.unary.general]{General} |
|
0 commit comments