#define CAT2(a, b) a ## b
#define CAT(a, b) CAT2(a, b)
#ifdef DEFINE_FIRST
#define DEF(x) auto CAT(a, __LINE__) = x
#else
#define DEF(x)
#endif
namespace std {
struct strong_ordering {
int n;
static const strong_ordering equal, less, greater;
};
constexpr strong_ordering strong_ordering::equal{0},
strong_ordering::less{-1}, strong_ordering::greater{1};
bool operator!=(std::strong_ordering o, int n) noexcept;
}
namespace Eq {
struct A {
bool operator==(const A&) const = default;
};
DEF(A() == A());
static_assert(noexcept(A() == A()));
struct B {
bool operator==(const B&) const;
};
struct C {
B b;
bool operator==(const C&) const = default;
};
DEF(C() == C());
static_assert(!noexcept(C() == C()));
template<typename T> struct D {
bool operator==(const D &) const {
typename T::error error; }
};
struct E {
D<E> d;
bool operator==(const E&) const = default;
};
static_assert(!noexcept(E() == E()));
struct F {
D<F> d;
bool operator==(const F&) const = default; };
bool equal = F() == F();
static_assert(!noexcept(F() == F()));
}
namespace Spaceship {
struct X {
friend std::strong_ordering operator<=>(X, X);
};
struct Y : X {
friend std::strong_ordering operator<=>(Y, Y) = default;
};
DEF(Y() <=> Y());
static_assert(!noexcept(Y() <=> Y()));
struct ThrowingCmpCat {
ThrowingCmpCat(std::strong_ordering);
operator std::strong_ordering();
};
bool operator!=(ThrowingCmpCat o, int n) noexcept;
struct A {
friend ThrowingCmpCat operator<=>(A, A) noexcept;
};
struct B {
A a;
std::strong_ordering operator<=>(const B&) const = default;
};
DEF(B() <=> B());
static_assert(!noexcept(B() <=> B()));
struct C {
int n;
ThrowingCmpCat operator<=>(const C&) const = default;
};
DEF(C() <=> C());
static_assert(!noexcept(C() <=> C()));
struct D {
int n;
std::strong_ordering operator<=>(const D&) const = default;
};
DEF(D() <=> D());
static_assert(noexcept(D() <=> D()));
struct ThrowingCmpCat2 {
ThrowingCmpCat2(std::strong_ordering) noexcept;
operator std::strong_ordering() noexcept;
};
bool operator!=(ThrowingCmpCat2 o, int n);
struct E {
friend ThrowingCmpCat2 operator<=>(E, E) noexcept;
};
struct F {
E e;
std::strong_ordering operator<=>(const F&) const = default;
};
DEF(F() <=> F());
static_assert(noexcept(F() <=> F()));
struct G {
int n;
ThrowingCmpCat2 operator<=>(const G&) const = default;
};
DEF(G() <=> G());
static_assert(!noexcept(G() <=> G()));
}
namespace Synth {
struct A {
friend bool operator==(A, A) noexcept;
friend bool operator<(A, A) noexcept;
};
struct B {
A a;
friend std::strong_ordering operator<=>(B, B) = default;
};
std::strong_ordering operator<=>(B, B) noexcept;
struct C {
friend bool operator==(C, C);
friend bool operator<(C, C) noexcept;
};
struct D {
C c;
friend std::strong_ordering operator<=>(D, D) = default; };
std::strong_ordering operator<=>(D, D) noexcept;
struct E {
friend bool operator==(E, E) noexcept;
friend bool operator<(E, E);
};
struct F {
E e;
friend std::strong_ordering operator<=>(F, F) = default; };
std::strong_ordering operator<=>(F, F) noexcept; }
namespace Secondary {
struct A {
friend bool operator==(A, A);
friend bool operator!=(A, A) = default;
friend int operator<=>(A, A);
friend bool operator<(A, A) = default; friend bool operator<=(A, A) = default; friend bool operator>(A, A) = default; friend bool operator>=(A, A) = default; };
bool operator!=(A, A) noexcept; bool operator<(A, A) noexcept; bool operator<=(A, A) noexcept; bool operator>(A, A) noexcept; bool operator>=(A, A) noexcept;
struct B {
friend bool operator==(B, B) noexcept;
friend bool operator!=(B, B) = default;
friend int operator<=>(B, B) noexcept;
friend bool operator<(B, B) = default;
friend bool operator<=(B, B) = default;
friend bool operator>(B, B) = default;
friend bool operator>=(B, B) = default;
};
bool operator!=(B, B) noexcept;
bool operator<(B, B) noexcept;
bool operator<=(B, B) noexcept;
bool operator>(B, B) noexcept;
bool operator>=(B, B) noexcept;
}
namespace DefineBeforeComputingExceptionSpec {
template<int> struct A {
A();
A(const A&) = delete; friend bool operator==(A, A); friend bool operator!=(const A&, const A&) = default; };
bool a0 = A<0>() != A<0>(); bool a1 = operator!=(A<1>(), A<1>());
template struct A<2>;
bool operator!=(const A<2>&, const A<2>&) noexcept;
template<int> struct B {
B();
B(const B&) = delete; friend bool operator==(B, B); bool operator!=(const B&) const = default; };
bool b0 = B<0>() != B<0>(); bool b1 = B<1>().operator!=(B<1>()); int b2 = sizeof(&B<2>::operator!=); }