On Wed, 18 Feb 2026 at 10:52, Tomasz Kamiński <[email protected]> wrote:
>
> This implements LWG4383 with LWG4500, LWG4523 follow-up corrections.
>
> This patch changes the constant_wrapper assignments operator (including
> compounds), increment and decrement to apply directly to value. In
> consequence the operators are only supported for types, for which above
> operations can be applied on const value.
>
> The operator() definition was updated for consistency.
OK (with this line removed as you already noted).
>
> libstdc++-v3/ChangeLog:
>
> * include/std/type_traits (_CWOperators::operator++)
> (_CWOperators::operator--, _CWOperators::operator+=)
> (_CWOperators::operator-=, _CWOperators::operator*=)
> (_CWOperators::operator/=, _CWOperators::operator%=)
> (_CWOperators::operator&=, _CWOperators::operator|=)
> (_CWOperators::operator^=, _CWOperators::operator<<=)
> (_CWOperators::operator>>=, constant_wrapper::operator=):
> Adjust definitions to apply operator on value.
> (_CWOpeators:::operator()): Updated defintion to keep
> it consistient.
> * testsuite/20_util/constant_wrapper/generic.cc:
> Remove test_pseudo_mutator.
> * testsuite/20_util/constant_wrapper/instantiate.cc:
> Test that operators are not provided if wrapped type
> do not support them, or provide mutable operators.
> ---
> v2 reverts unrelate changes to operator().
>
> libstdc++-v3/include/std/type_traits | 105 ++---
> .../20_util/constant_wrapper/generic.cc | 14 -
> .../20_util/constant_wrapper/instantiate.cc | 441 ++++++++++++------
> 3 files changed, 321 insertions(+), 239 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/type_traits
> b/libstdc++-v3/include/std/type_traits
> index ea700d1ed97..a7f881fe973 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -4606,128 +4606,86 @@ template<typename _Ret, typename _Fn, typename...
> _Args>
> template<_ConstExprParam _Tp>
> constexpr auto
> operator++(this _Tp) noexcept
> - requires requires(_Tp::value_type __x) { ++__x; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return ++__x; }()>{};
> - }
> + -> constant_wrapper<(++_Tp::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp>
> constexpr auto
> operator++(this _Tp, int) noexcept
> - requires requires(_Tp::value_type __x) { __x++; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x++; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value++)>
> + { return {}; }
>
> template<_ConstExprParam _Tp>
> constexpr auto
> operator--(this _Tp) noexcept
> - requires requires(_Tp::value_type __x) { --__x; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return --__x; }()>{};
> - }
> + -> constant_wrapper<(--_Tp::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp>
> constexpr auto
> operator--(this _Tp, int) noexcept
> - requires requires(_Tp::value_type __x) { __x--; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x--; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value--)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator+=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x += _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x += _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value += _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator-=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x -= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x -= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value -= _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator*=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x *= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x *= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value *= _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator/=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x /= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x /= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value /= _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator%=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x %= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x %= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value %= _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator&=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x &= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x &= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value &= _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator|=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x |= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x |= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value |= _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator^=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x ^= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x ^= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value ^= _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator<<=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x <<= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x <<= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value <<= _Right::value)>
> + { return {}; }
>
> template<_ConstExprParam _Tp, _ConstExprParam _Right>
> constexpr auto
> operator>>=(this _Tp, _Right) noexcept
> - requires requires(_Tp::value_type __x) { __x >>= _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = _Tp::value; return __x >>= _Right::value; }()>{};
> - }
> + -> constant_wrapper<(_Tp::value >>= _Right::value)>
> + { return {}; }
> };
>
> template<_CwFixedValue _Xv, typename>
> @@ -4740,11 +4698,8 @@ template<typename _Ret, typename _Fn, typename...
> _Args>
> template<_ConstExprParam _Right>
> constexpr auto
> operator=(_Right) const noexcept
> - requires requires(value_type __x) { __x = _Right::value; }
> - {
> - return constant_wrapper<
> - [] { auto __x = value; return __x = _Right::value; }()>{};
> - }
> + -> constant_wrapper<(value = _Right::value)>
> + { return {}; }
>
> constexpr
> operator decltype(value)() const noexcept
> diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc
> b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc
> index f632f8e285a..de4334b64f5 100644
> --- a/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc
> +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc
> @@ -241,19 +241,6 @@ test_member_pointer()
> check_same(((&decltype(co)::value)->*cdiv)(denom), expect_unwrapped);
> }
>
> -constexpr void
> -test_pseudo_mutator()
> -{
> - auto ci = std::cw<3>;
> - auto cmmi = --ci;
> - VERIFY(ci.value == 3);
> - VERIFY(cmmi.value == 2);
> -
> - auto cimm = ci--;
> - VERIFY(ci.value == 3);
> - VERIFY(cimm.value == 3);
> -}
> -
> struct Truthy
> {
> constexpr operator bool() const
> @@ -375,7 +362,6 @@ test_all()
> test_indexable2();
> test_indexable3();
> test_member_pointer();
> - test_pseudo_mutator();
> test_logic();
> test_three_way();
> test_equality();
> diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc
> b/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc
> index 4f1232598d6..5adf6fda5a3 100644
> --- a/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc
> +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc
> @@ -98,40 +98,85 @@ namespace member_ops
> };
> }
>
> +namespace mutable_ops
> +{
> + template<int OpId>
> + struct UnaryOps
> + {
> + constexpr int
> + operator+() noexcept requires (OpId == 0)
> + { return OpId; }
> +
> + constexpr int
> + operator-() noexcept requires (OpId == 1)
> + { return OpId; }
> +
> + constexpr int
> + operator~() noexcept requires (OpId == 2)
> + { return OpId; }
> +
> + constexpr int
> + operator!() noexcept requires (OpId == 3)
> + { return OpId; }
> +
> + constexpr int
> + operator&() noexcept requires (OpId == 4)
> + { return OpId; }
> +
> + constexpr int
> + operator*() noexcept requires (OpId == 5)
> + { return OpId; }
> +
> + constexpr int
> + operator++() noexcept requires (OpId == 6)
> + { return OpId; }
> +
> + constexpr int
> + operator++(int) noexcept requires (OpId == 7)
> + { return OpId; }
> +
> + constexpr int
> + operator--() noexcept requires (OpId == 8)
> + { return OpId; }
> +
> + constexpr int
> + operator--(int) noexcept requires (OpId == 9)
> + { return OpId; }
> + };
> +}
> +
> constexpr size_t n_unary_ops = 10;
>
> -template<template<int> typename Ops, int OpId>
> +template<template<int> typename Ops, int EnabledId, int ActiveId = EnabledId>
> constexpr void
> test_unary_operator()
> {
> - auto x = std::cw<Ops<OpId>{}>;
> + auto x = std::cw<Ops<EnabledId>{}>;
>
> auto check = [](auto c)
> {
> - VERIFY(c == OpId);
> - static_assert(std::same_as<decltype(c), std::constant_wrapper<OpId>>);
> + VERIFY(c == EnabledId);
> + static_assert(std::same_as<decltype(c),
> std::constant_wrapper<EnabledId>>);
> };
>
> - if constexpr (OpId == 0)
> - check(+x);
> - if constexpr (OpId == 1)
> - check(-x);
> - if constexpr (OpId == 2)
> - check(~x);
> - if constexpr (OpId == 3)
> - check(!x);
> - if constexpr (OpId == 4)
> +#define CHECK_EXPR(Id, Expr) \
> + if constexpr (ActiveId == Id) \
> + check(Expr); \
> + else \
> + static_assert(!requires { Expr; })
> +
> + CHECK_EXPR(0, +x);
> + CHECK_EXPR(1, -x);
> + CHECK_EXPR(2, ~x);
> + CHECK_EXPR(3, !x);
> + if constexpr (ActiveId == 4)
> check(&x);
> - if constexpr (OpId == 5)
> - check(*x);
> - if constexpr (OpId == 6)
> - check(++x);
> - if constexpr (OpId == 7)
> - check(x++);
> - if constexpr (OpId == 8)
> - check(--x);
> - if constexpr (OpId == 9)
> - check(x--);
> + CHECK_EXPR(5, *x);
> + CHECK_EXPR(6, ++x);
> + CHECK_EXPR(7, x++);
> + CHECK_EXPR(8, --x);
> + CHECK_EXPR(9, x--);
> +#undef CHECK_EXPR
>
> static_assert(n_unary_ops == 10);
> }
> @@ -143,6 +188,7 @@ test_unary_operators_all()
> {
> (test_unary_operator<free_ops::UnaryOps, Idx>(), ...);
> (test_unary_operator<member_ops::UnaryOps, Idx>(), ...);
> + (test_unary_operator<mutable_ops::UnaryOps, Idx, -1>(), ...);
> };
> run(std::make_index_sequence<n_unary_ops>());
> }
> @@ -393,77 +439,187 @@ namespace member_ops
> };
> }
>
> +namespace mutable_ops
> +{
> + template<int OpId>
> + struct BinaryOps
> + {
> + constexpr int
> + operator+(BinaryOps) noexcept requires (OpId == 0)
> + { return OpId; }
> +
> + constexpr int
> + operator-(BinaryOps) noexcept requires (OpId == 1)
> + { return OpId; }
> +
> + constexpr int
> + operator*(BinaryOps) noexcept requires (OpId == 2)
> + { return OpId; }
> +
> + constexpr int
> + operator/(BinaryOps) noexcept requires (OpId == 3)
> + { return OpId; }
> +
> + constexpr int
> + operator%(BinaryOps) noexcept requires (OpId == 4)
> + { return OpId; }
> +
> + constexpr int
> + operator<<(BinaryOps) noexcept requires (OpId == 5)
> + { return OpId; }
> +
> + constexpr int
> + operator>>(BinaryOps) noexcept requires (OpId == 6)
> + { return OpId; }
> +
> + constexpr int
> + operator&(BinaryOps) noexcept requires (OpId == 7)
> + { return OpId; }
> +
> + constexpr int
> + operator|(BinaryOps) noexcept requires (OpId == 8)
> + { return OpId; }
> +
> + constexpr int
> + operator^(BinaryOps) noexcept requires (OpId == 9)
> + { return OpId; }
> +
> + constexpr int
> + operator&&(BinaryOps) noexcept requires (OpId == 10)
> + { return OpId; }
> +
> + constexpr int
> + operator||(BinaryOps) noexcept requires (OpId == 11)
> + { return OpId; }
> +
> + constexpr int
> + operator<=>(BinaryOps) noexcept requires (OpId == 12)
> + { return OpId; }
> +
> + constexpr int
> + operator<(BinaryOps) noexcept requires (OpId == 13)
> + { return OpId; }
> +
> + constexpr int
> + operator<=(BinaryOps) noexcept requires (OpId == 14)
> + { return OpId; }
> +
> + constexpr int
> + operator==(BinaryOps) noexcept requires (OpId == 15)
> + { return OpId; }
> +
> + constexpr int
> + operator!=(BinaryOps) noexcept requires (OpId == 16)
> + { return OpId; }
> +
> + constexpr int
> + operator>(BinaryOps) noexcept requires (OpId == 17)
> + { return OpId; }
> +
> + constexpr int
> + operator>=(BinaryOps) noexcept requires (OpId == 18)
> + { return OpId; }
> +
> + constexpr int
> + operator+=(BinaryOps) noexcept requires (OpId == 19)
> + { return OpId; }
> +
> + constexpr int
> + operator-=(BinaryOps) noexcept requires (OpId == 20)
> + { return OpId; }
> +
> + constexpr int
> + operator*=(BinaryOps) noexcept requires (OpId == 21)
> + { return OpId; }
> +
> + constexpr int
> + operator/=(BinaryOps) noexcept requires (OpId == 22)
> + { return OpId; }
> +
> + constexpr int
> + operator%=(BinaryOps) noexcept requires (OpId == 23)
> + { return OpId; }
> +
> + constexpr int
> + operator&=(BinaryOps) noexcept requires (OpId == 24)
> + { return OpId; }
> +
> + constexpr int
> + operator|=(BinaryOps) noexcept requires (OpId == 25)
> + { return OpId; }
> +
> + constexpr int
> + operator^=(BinaryOps) noexcept requires (OpId == 26)
> + { return OpId; }
> +
> + constexpr int
> + operator<<=(BinaryOps) noexcept requires (OpId == 27)
> + { return OpId; }
> +
> + constexpr int
> + operator>>=(BinaryOps) noexcept requires (OpId == 28)
> + { return OpId; }
> + };
> +}
> +
> constexpr size_t n_binary_ops = 29;
>
> -template<template<int> typename Ops, int OpId>
> +template<template<int> typename Ops, int EnabledId, int ActiveId = EnabledId>
> constexpr void
> test_binary_operator()
> {
> - auto cx = std::cw<Ops<OpId>{}>;
> - auto cy = std::cw<Ops<OpId>{}>;
> + auto cx = std::cw<Ops<EnabledId>{}>;
> + auto cy = std::cw<Ops<EnabledId>{}>;
>
> - auto check = [](auto c)
> + auto check = []<typename ResultT>(auto c, ResultT)
> {
> - VERIFY(c == OpId);
> - static_assert(std::same_as<decltype(c), std::constant_wrapper<OpId>>);
> + VERIFY(c == ResultT::value);
> + static_assert(std::same_as<decltype(c), ResultT>);
> };
>
> - if constexpr (OpId == 0)
> - check(cx + cy);
> - if constexpr (OpId == 1)
> - check(cx - cy);
> - if constexpr (OpId == 2)
> - check(cx * cy);
> - if constexpr (OpId == 3)
> - check(cx / cy);
> - if constexpr (OpId == 4)
> - check(cx % cy);
> - if constexpr (OpId == 5)
> - check(cx << cy);
> - if constexpr (OpId == 6)
> - check(cx >> cy);
> - if constexpr (OpId == 7)
> - check(cx & cy);
> - if constexpr (OpId == 8)
> - check(cx | cy);
> - if constexpr (OpId == 10)
> - check(cx && cy);
> - if constexpr (OpId == 11)
> - check(cx || cy);
> - if constexpr (OpId == 12)
> - check(cx <=> cy);
> - if constexpr (OpId == 13)
> - check(cx < cy);
> - if constexpr (OpId == 14)
> - check(cx <= cy);
> - if constexpr (OpId == 15)
> - check(cx == cy);
> - if constexpr (OpId == 16)
> - check(cx != cy);
> - if constexpr (OpId == 17)
> - check(cx > cy);
> - if constexpr (OpId == 18)
> - check(cx >= cy);
> - if constexpr (OpId == 19)
> - check(cx += cy);
> - if constexpr (OpId == 20)
> - check(cx -= cy);
> - if constexpr (OpId == 21)
> - check(cx *= cy);
> - if constexpr (OpId == 22)
> - check(cx /= cy);
> - if constexpr (OpId == 23)
> - check(cx %= cy);
> - if constexpr (OpId == 24)
> - check(cx &= cy);
> - if constexpr (OpId == 25)
> - check(cx |= cy);
> - if constexpr (OpId == 26)
> - check(cx ^= cy);
> - if constexpr (OpId == 27)
> - check(cx <<= cy);
> - if constexpr (OpId == 28)
> - check(cx >>= cy);
> +#define CHECK_OP(Id, Op) \
> + if constexpr (ActiveId == Id) \
> + check(cx Op cy, std::cw<Id>); \
> + else \
> + static_assert(!requires { cx Op cy; })
> +
> +#define CHECK_OP_F(Id, Op, Fb) \
> + if constexpr (ActiveId == Fb) \
> + check(cx Op cy, std::cw<(Fb Op 0)>); \
> + else CHECK_OP(Id, Op)
> +
> + CHECK_OP( 0, +);
> + CHECK_OP( 1, -);
> + CHECK_OP( 2, *);
> + CHECK_OP( 3, /);
> + CHECK_OP( 4, %);
> + CHECK_OP( 5, <<);
> + CHECK_OP( 6, >>);
> + CHECK_OP( 7, &);
> + CHECK_OP( 8, |);
> + CHECK_OP( 9, ^);
> + CHECK_OP(10, &&);
> + CHECK_OP(11, ||);
> + CHECK_OP(12, <=>);
> + CHECK_OP_F(13, <, 12);
> + CHECK_OP_F(14, <=, 12);
> + CHECK_OP_F(17, >, 12);
> + CHECK_OP_F(18, >=, 12);
> + CHECK_OP(15, ==);
> + CHECK_OP(16, !=);
> + CHECK_OP(19, +=);
> + CHECK_OP(20, -=);
> + CHECK_OP(21, *=);
> + CHECK_OP(22, /=);
> + CHECK_OP(23, %=);
> + CHECK_OP(24, &=);
> + CHECK_OP(25, |=);
> + CHECK_OP(26, ^=);
> + CHECK_OP(27, <<=);
> + CHECK_OP(28, >>=);
> +#undef CHECK_OP_F
> +#undef CHECK_OP
> +
> static_assert(n_binary_ops == 29);
> }
>
> @@ -476,74 +632,58 @@ template<template<int> typename Ops, int OpId>
> constexpr auto y = Ops<OpId>{};
> auto cy = std::cw<y>;
>
> - auto check = [](auto vc, auto cv)
> + auto check = []<typename ResT>(auto vc, auto cv, ResT res)
> {
> - auto impl = [](auto c)
> - {
> - VERIFY(c == OpId);
> - static_assert(std::same_as<decltype(c), int>);
> - };
> -
> - impl(vc);
> - impl(cv);
> + VERIFY(vc == res);
> + static_assert(std::same_as<decltype(vc), ResT>);
> +
> + VERIFY(cv == res);
> + static_assert(std::same_as<decltype(cv), ResT>);
> };
>
> - if constexpr (OpId == 0)
> - check(x + cy, cx + y);
> - if constexpr (OpId == 1)
> - check(x - cy, cx - y);
> - if constexpr (OpId == 2)
> - check(x * cy, cx * y);
> - if constexpr (OpId == 3)
> - check(x / cy, cx / y);
> - if constexpr (OpId == 4)
> - check(x % cy, cx % y);
> - if constexpr (OpId == 5)
> - check(x << cy, cx << y);
> - if constexpr (OpId == 6)
> - check(x >> cy, cx >> y);
> - if constexpr (OpId == 7)
> - check(x & cy, cx & y);
> - if constexpr (OpId == 8)
> - check(x | cy, cx | y);
> - if constexpr (OpId == 10)
> - check(x && cy, cx && y);
> - if constexpr (OpId == 11)
> - check(x || cy, cx || y);
> - if constexpr (OpId == 12)
> - check(x <=> cy, cx <=> y);
> - if constexpr (OpId == 13)
> - check(x < cy, cx < y);
> - if constexpr (OpId == 14)
> - check(x <= cy, cx <= y);
> - if constexpr (OpId == 15)
> - check(x == cy, cx == y);
> - if constexpr (OpId == 16)
> - check(x != cy, cx != y);
> - if constexpr (OpId == 17)
> - check(x > cy, cx > y);
> - if constexpr (OpId == 18)
> - check(x >= cy, cx >= y);
> - if constexpr (OpId == 19)
> - check(x += cy, cx += y);
> - if constexpr (OpId == 20)
> - check(x -= cy, cx -= y);
> - if constexpr (OpId == 21)
> - check(x *= cy, cx *= y);
> - if constexpr (OpId == 22)
> - check(x /= cy, cx /= y);
> - if constexpr (OpId == 23)
> - check(x %= cy, cx %= y);
> - if constexpr (OpId == 24)
> - check(x &= cy, cx &= y);
> - if constexpr (OpId == 25)
> - check(x |= cy, cx |= y);
> - if constexpr (OpId == 26)
> - check(x ^= cy, cx ^= y);
> - if constexpr (OpId == 27)
> - check(x <<= cy, cx <<= y);
> - if constexpr (OpId == 28)
> - check(x >>= cy, cx >>= y);
> +#define CHECK_OP(Id, Op) \
> + if constexpr (OpId == Id) \
> + check(x Op cy, cx Op y, Id); \
> + else \
> + static_assert(!requires { x Op cy; } && !requires { cx Op y; })
> +
> +#define CHECK_OP_F(Id, Op, Fb) \
> + if constexpr (OpId == Fb) \
> + check(x Op cy, cx Op y, Id Op 0); \
> + else CHECK_OP(Id, Op)
> +
> + CHECK_OP( 0, +);
> + CHECK_OP( 1, -);
> + CHECK_OP( 2, *);
> + CHECK_OP( 3, /);
> + CHECK_OP( 4, %);
> + CHECK_OP( 5, <<);
> + CHECK_OP( 6, >>);
> + CHECK_OP( 7, &);
> + CHECK_OP( 8, |);
> + CHECK_OP( 9, ^);
> + CHECK_OP(10, &&);
> + CHECK_OP(11, ||);
> + CHECK_OP(12, <=>);
> + CHECK_OP_F(13, <, 12);
> + CHECK_OP_F(14, <=, 12);
> + CHECK_OP_F(17, >, 12);
> + CHECK_OP_F(18, >=, 12);
> + CHECK_OP(15, ==);
> + CHECK_OP(16, !=);
> + CHECK_OP(19, +=);
> + CHECK_OP(20, -=);
> + CHECK_OP(21, *=);
> + CHECK_OP(22, /=);
> + CHECK_OP(23, %=);
> + CHECK_OP(24, &=);
> + CHECK_OP(25, |=);
> + CHECK_OP(26, ^=);
> + CHECK_OP(27, <<=);
> + CHECK_OP(28, >>=);
> +#undef CHECK_OP_F
> +#undef CHECK_OP
> +
> static_assert(n_binary_ops == 29);
> }
>
> @@ -555,6 +695,7 @@ test_binary_operators_all()
> (test_binary_operator<free_ops::BinaryOps, Idx>(), ...);
> (test_mixed_binary_operators<free_ops::BinaryOps, Idx>(), ...);
> (test_binary_operator<member_ops::BinaryOps, Idx>(), ...);
> + (test_binary_operator<mutable_ops::BinaryOps, Idx, -1>(), ...);
> };
> run(std::make_index_sequence<n_binary_ops>());
> }
> --
> 2.53.0
>