template <typename T>
concept HasEq = requires(T t) {
{ t == t } -> std::convertible_to<bool>;
};
struct X {};
static_assert(not HasEq<X>);
//bool a = pair<X, X>{} == pair<X, X>{};
static_assert(! HasEq<pair<X, X>>); // fails! SIGH
I suppose it’s simple enough to define a concept for 'T has support for =='. And it’s simple enough to define a type 'X' which doesn't support the operator==. And the concept seems to work fine for that.
But it is confusing that pair<X,X> doesn't really support operator== (since it delegates to the X operator== that doesn’t exist).
And yet HasEq<pair<X, X>> returns the wrong answer (it says operator== is defined).
This appears to be a bug with the std C++ definitions of operator==(pair,pair), defining operator== unconditionally, instead of using 'enable_if' or 'requires' on the operator== definition. But I'm not really sure what I can do about that to make HasEq work properly (so it would start with understanding if this is really a defect in the std::pair operator== definition).
OK, I may have found an answer (thanks to hints in comments above!), but it makes me feel I need to bathe.
https://godbolt.org/z/3crzGdvP5
#include <concepts>
#include <utility>
using namespace std;
namespace PRIVATE_ {
template <typename T>
concept HasEqBasic = requires(T t) {
{ t == t } -> std::convertible_to<bool>;
};
template <typename T>
constexpr inline bool has_eq_v = HasEqBasic<T>;
template <typename T, typename U>
constexpr inline bool has_eq_v<std::pair<T, U>> = has_eq_v<T> and has_eq_v<U>;
template <typename... Ts>
constexpr inline bool has_eq_v<std::tuple<Ts...>> = (has_eq_v<Ts> and ...);
} // namespace PRIVATE_
template <typename T>
concept HasEq = PRIVATE_::has_eq_v<T>;
struct X {};
static_assert(not HasEq<X>);
static_assert(!HasEq<pair<X, X>>);