如何做简单的C++概念has_eq -与std::pair一起工作(对于C++20来说是std::pair operator== broken)

rryofs0p  于 2023-06-25  发布在  其他
关注(0)|答案(2)|浏览(128)

Compiler Explorer link

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

我想定义一个'T has support for =='的概念是很简单的。定义一个不支持运算符==的类型'X'是很简单的。这个概念似乎很好地实现了这一点。
但令人困惑的是,对<X,X>并不真正支持operator==(因为它委托给不存在的X操作符==)。
然而,HasEq<pair<X,X>>返回错误的答案(它说operator==已定义)。
这个 * 看起来 * 是operator==(pair,pair)的标准C++定义的一个bug,它无条件地定义operator==,而不是在operator==定义上使用'enable_if'或'requires'。但是我不确定我能做些什么来使HasEq正常工作(所以首先要理解这是否真的是std::pair operator==定义中的缺陷)。

iovurdzv

iovurdzv1#

好吧,我 * 可能 * 已经找到了答案(感谢上面评论中的提示!),但这让我觉得我需要洗澡。
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>>);
r1wp621o

r1wp621o2#

经过一番折腾,我想出了这个。聪明的人会告诉我它可能有什么问题:

template <typename T>
concept BasicHasEq = requires(T t) {
    { t == t } -> std::convertible_to <bool>;
};

template <typename T>
concept IsPair = requires (T t) {
    t.first;
    t.second;
};

template <typename T>
concept IsNonComparablePair = IsPair <T> &&
    (!BasicHasEq <decltype (std::declval <T> ().first)> ||
     !BasicHasEq <decltype (std::declval <T> ().second)>);

template <typename T>
concept IsContainer = requires (T t) {
    typename T::value_type;    
};    
    
template <typename T>
concept IsNonCopyableContainer = IsContainer <T> && !BasicHasEq <typename T::value_type>;

template <typename T>
concept HasEq = BasicHasEq <T> && !IsNonComparablePair <T> && !IsNonCopyableContainer <T>;

Live demo
编辑后还可以处理容器类型。可能还需要做更多的工作来处理所有可能发生的事情。

相关问题