blob: ec47552c47534ae60533e2b8b92cca99de13d2c6 [file] [log] [blame]
// { dg-do compile { target c++20 } }
#include <optional>
#ifndef __cpp_lib_constrained_equality
# error "Feature-test macro for constrained_equality missing"
#elif __cpp_lib_constrained_equality < 202403L
# error "Feature-test macro for constrained_equality has wrong value"
#endif
template<typename T, typename U>
concept eq_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t == u;
*t == u;
t == *u;
};
template<typename T, typename U = T>
concept eq_comparable =
eq_comparable_impl<T, U>
#if __cplusplus > 202302l
&& eq_comparable_impl<T&, U&>
&& eq_comparable_impl<T const&, U const&>
&& eq_comparable_impl<T const&, U&>
&& eq_comparable_impl<T, U const&>
&& eq_comparable_impl<T&, U>
#endif
;
template<typename T, typename U>
concept ne_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t != u;
*t != u;
t != *u;
};
template<typename T, typename U = T>
concept ne_comparable =
ne_comparable_impl<T, U>
#if __cplusplus > 202302l
&& ne_comparable_impl<T&, U&>
&& ne_comparable_impl<T const&, U const&>
&& ne_comparable_impl<T const&, U&>
&& ne_comparable_impl<T, U const&>
&& ne_comparable_impl<T&, U>
#endif
;
template<typename T, typename U>
concept lt_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t < u;
*t < u;
t < *u;
};
template<typename T, typename U = T>
concept lt_comparable =
lt_comparable_impl<T, U>
#if __cplusplus > 202302l
&& lt_comparable_impl<T&, U&>
&& lt_comparable_impl<T const&, U const&>
&& lt_comparable_impl<T const&, U&>
&& lt_comparable_impl<T, U const&>
&& lt_comparable_impl<T&, U>
#endif
;
template<typename T, typename U>
concept le_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t <= u;
*t <= u;
t <= *u;
};
template<typename T, typename U = T>
concept le_comparable =
le_comparable_impl<T, U>
#if __cplusplus > 202302l
&& le_comparable_impl<T&, U&>
&& le_comparable_impl<T const&, U const&>
&& le_comparable_impl<T const&, U&>
&& le_comparable_impl<T, U const&>
&& le_comparable_impl<T&, U>
#endif
;
template<typename T, typename U>
concept gt_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t > u;
*t > u;
t > *u;
};
template<typename T, typename U = T>
concept gt_comparable =
gt_comparable_impl<T, U>
#if __cplusplus > 202302l
&& gt_comparable_impl<T&, U&>
&& gt_comparable_impl<T const&, U const&>
&& gt_comparable_impl<T const&, U&>
&& gt_comparable_impl<T, U const&>
&& gt_comparable_impl<T&, U>
#endif
;
template<typename T, typename U>
concept ge_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t >= u;
*t >= u;
t >= *u;
};
template<typename T, typename U = T>
concept ge_comparable =
ge_comparable_impl<T, U>
#if __cplusplus > 202302l
&& ge_comparable_impl<T&, U&>
&& ge_comparable_impl<T const&, U const&>
&& ge_comparable_impl<T const&, U&>
&& ge_comparable_impl<T, U const&>
&& ge_comparable_impl<T&, U>
#endif
;
static_assert( eq_comparable<int> );
static_assert( ne_comparable<int> );
static_assert( lt_comparable<int> );
static_assert( le_comparable<int> );
static_assert( gt_comparable<int> );
static_assert( ge_comparable<int> );
static_assert( eq_comparable<int, long> );
static_assert( ne_comparable<int, long> );
static_assert( lt_comparable<int, long> );
static_assert( le_comparable<int, long> );
static_assert( gt_comparable<int, long> );
static_assert( ge_comparable<int, long> );
static_assert( eq_comparable<short, int> );
static_assert( ne_comparable<short, int> );
static_assert( lt_comparable<short, int> );
static_assert( le_comparable<short, int> );
static_assert( gt_comparable<short, int> );
static_assert( ge_comparable<short, int> );
struct A { };
static_assert( ! eq_comparable<A> );
static_assert( ! ne_comparable<A> );
static_assert( ! lt_comparable<A> );
static_assert( ! le_comparable<A> );
static_assert( ! gt_comparable<A> );
static_assert( ! ge_comparable<A> );
static_assert( ! eq_comparable<A, A> );
static_assert( ! ne_comparable<A, A> );
static_assert( ! lt_comparable<A, A> );
static_assert( ! le_comparable<A, A> );
static_assert( ! gt_comparable<A, A> );
static_assert( ! ge_comparable<A, A> );
static_assert( ! eq_comparable<A, int> );
static_assert( ! ne_comparable<A, int> );
static_assert( ! lt_comparable<A, int> );
static_assert( ! le_comparable<A, int> );
static_assert( ! gt_comparable<A, int> );
static_assert( ! ge_comparable<A, int> );
struct B { };
void operator==(B, B);
static_assert( ! eq_comparable<B> );
static_assert( ! ne_comparable<B> );
static_assert( ! lt_comparable<B> );
static_assert( ! le_comparable<B> );
static_assert( ! gt_comparable<B> );
static_assert( ! ge_comparable<B> );
static_assert( ! eq_comparable<B, B> );
static_assert( ! ne_comparable<B, B> );
static_assert( ! lt_comparable<B, B> );
static_assert( ! le_comparable<B, B> );
static_assert( ! gt_comparable<B, B> );
static_assert( ! ge_comparable<B, B> );
static_assert( ! eq_comparable<B, int> );
static_assert( ! ne_comparable<B, int> );
static_assert( ! lt_comparable<B, int> );
static_assert( ! le_comparable<B, int> );
static_assert( ! gt_comparable<B, int> );
static_assert( ! ge_comparable<B, int> );
struct C { };
bool operator==(C, C);
static_assert( eq_comparable<C> );
static_assert( ne_comparable<C> );
static_assert( ! lt_comparable<C> );
static_assert( ! le_comparable<C> );
static_assert( ! gt_comparable<C> );
static_assert( ! ge_comparable<C> );
static_assert( eq_comparable<C, C> );
static_assert( ne_comparable<C, C> );
static_assert( eq_comparable<C, C> );
static_assert( ne_comparable<C, C> );
struct D { };
int operator==(D, D);
bool operator!=(D, D) = delete;
static_assert( eq_comparable<D> );
static_assert( ! ne_comparable<D> );
static_assert( ! lt_comparable<D> );
static_assert( ! le_comparable<D> );
static_assert( ! gt_comparable<D> );
static_assert( ! ge_comparable<D> );
static_assert( eq_comparable<D, D> );
static_assert( ! ne_comparable<D, D> );
static_assert( eq_comparable<D, D> );
static_assert( ! ne_comparable<D, D> );
struct E { };
bool operator==(/* not-const */ E&, const E&);
static_assert( ! eq_comparable<E> );
static_assert( ! ne_comparable<E> );
static_assert( ! lt_comparable<E> );
static_assert( ! le_comparable<E> );
static_assert( ! gt_comparable<E> );
static_assert( ! ge_comparable<E> );
static_assert( ! eq_comparable<E, E> );
static_assert( ! eq_comparable<E, E> );
struct F { };
bool operator<(F, F);
void operator>(F, F);
static_assert( ! eq_comparable<F> );
static_assert( ! ne_comparable<F> );
static_assert( lt_comparable<F> );
static_assert( ! le_comparable<F> );
static_assert( ! gt_comparable<F> );
static_assert( ! ge_comparable<F> );
static_assert( lt_comparable<F, F> );
static_assert( lt_comparable<F, F> );
struct G { };
bool operator<=(G, G);
void operator<(G, G);
static_assert( ! eq_comparable<G> );
static_assert( ! ne_comparable<G> );
static_assert( ! lt_comparable<G> );
static_assert( le_comparable<G> );
static_assert( ! gt_comparable<G> );
static_assert( ! ge_comparable<G> );
static_assert( le_comparable<G, G> );
static_assert( le_comparable<G, G> );
struct H { };
bool operator>(H, H);
void operator>=(H, H);
static_assert( ! eq_comparable<H> );
static_assert( ! ne_comparable<H> );
static_assert( ! lt_comparable<H> );
static_assert( ! le_comparable<H> );
static_assert( gt_comparable<H> );
static_assert( ! ge_comparable<H> );
static_assert( gt_comparable<H, H> );
static_assert( gt_comparable<H, H> );
struct I { };
bool operator>=(I, I);
void operator<=(I, I);
static_assert( ! eq_comparable<I> );
static_assert( ! ne_comparable<I> );
static_assert( ! lt_comparable<I> );
static_assert( ! le_comparable<I> );
static_assert( ! gt_comparable<I> );
static_assert( ge_comparable<I> );
static_assert( ge_comparable<I, I> );
static_assert( ge_comparable<I, I> );
struct J { };
bool operator==(J, J);
std::weak_ordering operator<=>(J, J);
static_assert( eq_comparable<J> );
static_assert( ne_comparable<J> );
static_assert( lt_comparable<J> );
static_assert( le_comparable<J> );
static_assert( gt_comparable<J> );
static_assert( ge_comparable<J> );
struct K { };
int operator==(K, K); // non-bool prevents synthesis of !=
void operator<=(K, K);
std::weak_ordering operator<=>(K, K);
static_assert( eq_comparable<K> );
static_assert( ! ne_comparable<K> );
static_assert( lt_comparable<K> );
static_assert( ! le_comparable<K> );
static_assert( gt_comparable<K> );
static_assert( ge_comparable<K> );
bool operator==(A, B);
static_assert( eq_comparable<A, B> );
static_assert( eq_comparable<B, A> );
static_assert( ne_comparable<A, B> );
static_assert( ne_comparable<B, A> );
static_assert( ! lt_comparable<A, B> );
static_assert( ! le_comparable<A, B> );
static_assert( ! gt_comparable<A, B> );
static_assert( ! ge_comparable<A, B> );
int operator==(C, D); // non-bool prevents synthesis of != and reversed args
static_assert( eq_comparable<C, D> );
static_assert( ! eq_comparable<D, C> );
static_assert( ! ne_comparable<C, D> );
static_assert( ! ne_comparable<D, C> );
static_assert( ! lt_comparable<C, D> );
static_assert( ! le_comparable<C, D> );
static_assert( ! gt_comparable<C, D> );
static_assert( ! ge_comparable<C, D> );
std::weak_ordering operator<=>(E, F);
static_assert( ! eq_comparable<E, F> );
static_assert( ! eq_comparable<F, E> );
static_assert( ! ne_comparable<E, F> );
static_assert( ! ne_comparable<F, E> );
static_assert( lt_comparable<E, F> );
static_assert( le_comparable<E, F> );
static_assert( gt_comparable<E, F> );
static_assert( ge_comparable<E, F> );
static_assert( lt_comparable<F, E> );
static_assert( le_comparable<F, E> );
static_assert( gt_comparable<F, E> );
static_assert( ge_comparable<F, E> );