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

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

Compiler Explorer link

  1. template <typename T>
  2. concept HasEq = requires(T t) {
  3. { t == t } -> std::convertible_to<bool>;
  4. };
  5. struct X {};
  6. static_assert(not HasEq<X>);
  7. //bool a = pair<X, X>{} == pair<X, X>{};
  8. 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

  1. #include <concepts>
  2. #include <utility>
  3. using namespace std;
  4. namespace PRIVATE_ {
  5. template <typename T>
  6. concept HasEqBasic = requires(T t) {
  7. { t == t } -> std::convertible_to<bool>;
  8. };
  9. template <typename T>
  10. constexpr inline bool has_eq_v = HasEqBasic<T>;
  11. template <typename T, typename U>
  12. constexpr inline bool has_eq_v<std::pair<T, U>> = has_eq_v<T> and has_eq_v<U>;
  13. template <typename... Ts>
  14. constexpr inline bool has_eq_v<std::tuple<Ts...>> = (has_eq_v<Ts> and ...);
  15. } // namespace PRIVATE_
  16. template <typename T>
  17. concept HasEq = PRIVATE_::has_eq_v<T>;
  18. struct X {};
  19. static_assert(not HasEq<X>);
  20. static_assert(!HasEq<pair<X, X>>);
展开查看全部
r1wp621o

r1wp621o2#

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

  1. template <typename T>
  2. concept BasicHasEq = requires(T t) {
  3. { t == t } -> std::convertible_to <bool>;
  4. };
  5. template <typename T>
  6. concept IsPair = requires (T t) {
  7. t.first;
  8. t.second;
  9. };
  10. template <typename T>
  11. concept IsNonComparablePair = IsPair <T> &&
  12. (!BasicHasEq <decltype (std::declval <T> ().first)> ||
  13. !BasicHasEq <decltype (std::declval <T> ().second)>);
  14. template <typename T>
  15. concept IsContainer = requires (T t) {
  16. typename T::value_type;
  17. };
  18. template <typename T>
  19. concept IsNonCopyableContainer = IsContainer <T> && !BasicHasEq <typename T::value_type>;
  20. template <typename T>
  21. concept HasEq = BasicHasEq <T> && !IsNonComparablePair <T> && !IsNonCopyableContainer <T>;

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

展开查看全部

相关问题