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