如何做简单的 C++ 概念 has_eq - 与 std::pair 一起使用(对于 C++20,std::pair 运算符 == 已损坏)

lew*_*wis 19 c++ concept

编译器资源管理器链接

\n
template <typename T>\nconcept HasEq = requires(T t) {\n    { t == t } -> std::convertible_to<bool>;\n};\n\nstruct X {};\nstatic_assert(not HasEq<X>);\n//bool a = pair<X, X>{} == pair<X, X>{};\nstatic_assert(! HasEq<pair<X, X>>);  // fails! SIGH\n
Run Code Online (Sandbox Code Playgroud)\n

我想它\xe2\x80\x99 足够简单,可以定义一个概念“T 支持==”。它\xe2\x80\x99很简单,可以定义一个不支持运算符==的类型\'X\'。这个概念似乎对此很有效。

\n

但令人困惑的是,pair<X,X> 并不真正支持运算符==(因为它委托给不存在的X 运算符==)。

\n

然而 HasEq<pair<X, X>> 返回错误的答案(它表示已经定义了operator==)。

\n

似乎是 std C++ 运算符 ==(pair,pair) 定义的错误,无条件定义运算符 ==,而不是在运算符 == 定义上使用 \'enable_if\' 或 \'requires\'。但我不太确定我能做些什么来使 HasEq 正常工作(所以首先要了解这是否确实是 st​​d::pair 运算符== 定义中的缺陷)。

\n

lew*_*wis 11

好吧,我可能已经找到了答案(感谢上面评论中的提示!),但这让我觉得我需要洗澡。

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>>);
Run Code Online (Sandbox Code Playgroud)


Pau*_*ers 5

经过一番修补后,我想出了这个。聪明的头脑会告诉我它可能出了什么问题:

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>;
Run Code Online (Sandbox Code Playgroud)

现场演示


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