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.
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