如何告诉编译器MyCustomType与SomeOtherType是equal_comparable_with? [英] How can I tell the compiler that MyCustomType is equality_comparable_with SomeOtherType?
问题描述
假设我有一个 MyCustomType
与 SomeOtherType
进行了比较:
Suppose I have a MyCustomType
that has comparisons with SomeOtherType
:
struct SomeOtherType {
int value;
constexpr bool operator==(const SomeOtherType& rhs) const = default;
};
struct MyCustomType {
int x;
constexpr bool operator==(const MyCustomType& rhs) const = default;
constexpr bool operator==(const SomeOtherType& rhs) const {
return x == rhs.value;
}
friend constexpr bool operator==(const SomeOtherType& lhs, const MyCustomType& rhs) {
return lhs.value == rhs.x;
}
};
这很好,但是 static_assert(std :: equality_comparable_with< MyCustomType,SomeOtherType>);
失败,这意味着我不能在 std :: ranges中将它们用于异构查找
算法:
This is great, but static_assert(std::equality_comparable_with<MyCustomType, SomeOtherType>);
fails, meaning that I can't use them for heterogenous lookup in the std::ranges
algorithms:
error: no type named 'type' in 'struct std::common_reference<const MyCustomType&, const SomeOtherType&>'
我了解失败的原因:我们可能有一个 operator ==
,但是我们不满足通用参考要求(另请参见).但是,实际上,我的类型与 SomeOtherType
相等.我如何说服编译器是这种情况?
I understand why this fails: we may have an operator==
, but we don't meet the common-reference requirements (see also Does `equality_comparable_with` need to require `common_reference`? ). However, my type is, practically speaking, equality comparable with SomeOtherType
. How can I convince the compiler that this is the case?
推荐答案
从哲学上讲, std :: equality_comparable_with
的公共引用要求是对编写异类时所做的隐式声明进行显式编码.运算符==(T,U)
实际上表示相等*:有一些常见的超类型" T
union U
"为此, operator ==
是相等的.此" T
联合 U
"在 MyCustomType
和 SomeOtherType
的代码中实际上并不存在.如果我们通过专门化 std :: common_reference_t
来使类型实际存在,那么我们就可以满足 std :: equality_comparable_with
.
Philosophically, the common-reference requirements of std::equality_comparable_with
are explicitly encoding the implicit statement made when writing a heterogenous operator==(T, U)
to actually mean equality*: there is some common supertype "T
union U
" for which the operator==
is equality. This "T
union U
" doesn't actually exist in the code for MyCustomType
and SomeOtherType
. If we make the type actually exist by specializing std::common_reference_t
, then we can meet std::equality_comparable_with
.
*某些类型使用 operator ==
来实现等价而不是相等(例如,迭代器+前哨),因此不应该并且也不满足 std :: equality_comparable_with
.
*Some types use operator==
for equivalence rather than equality (e.g. iterators+sentinels), and as such should not and do not meet std::equality_comparable_with
.
我们可以使用 std :: basic_common_reference
用于指定代理引用的自定义点:
We can use the std::basic_common_reference
customization point to specify a proxy reference:
类模板
basic_common_reference
是一个自定义点,允许用户影响用户定义类型(通常是代理引用)的common_reference
的结果.
The class template
basic_common_reference
is a customization point that allows users to influence the result ofcommon_reference
for user-defined types (typically proxy references).
要使其正常工作,我们需要:
For this to work, we need:
-
eq_proxy_ref< T>
,其作用类似于T
的引用. -
MyCustomType
必须可以隐式转换为eq_proxy_ref< T>
. -
SomeOtherType
必须隐式转换为eq_proxy_ref< T>
. -
basic_common_reference
和SomeOtherType
必须返回此eq_proxy_ref< int>
.如果您想避免泄漏MyCustomType
的内部信息,则eq_proxy_ref< MyCustomProxy>
也可以工作. -
eq_proxy_ref< T>
之间必须具有比较运算符. -
eq_proxy_ref< T>
必须遵守要求的精神.
MyCustomType
的eq_proxy_ref<T>
which acts like a reference forT
.MyCustomType
must be implicitly convertible toeq_proxy_ref<T>
.SomeOtherType
must be implicitly convertible toeq_proxy_ref<T>
.basic_common_reference
ofMyCustomType
andSomeOtherType
must return thiseq_proxy_ref<int>
. Aeq_proxy_ref<MyCustomProxy>
could work too if you wanted to avoid leaking the internals ofMyCustomType
.eq_proxy_ref<T>
must have comparison operators between itself.eq_proxy_ref<T>
must obey the spirit of the requirement.
满足这些约束的示例如下:
An example meeting these constraints follows:
#include <concepts>
#include <type_traits>
// Assuming you don't own SomeOtherType:
template <typename T>
class MyCustomTypeEqProxy {
template <typename>
friend class MyCustomTypeEqProxy;
private:
T ref_;
public:
template <typename U>
requires std::convertible_to<U, T>
constexpr MyCustomTypeEqProxy(U ref)
: ref_(ref)
{}
constexpr MyCustomTypeEqProxy(const SomeOtherType& rhs)
requires std::convertible_to<const int&, T>
: ref_(rhs.value)
{}
template <typename U>
requires std::equality_comparable_with<T, U>
constexpr bool operator==(const MyCustomTypeEqProxy<U>& rhs) const {
return ref_ == rhs.ref_;
};
};
struct MyCustomType {
int x;
constexpr bool operator==(const MyCustomType& rhs) const = default;
constexpr bool operator==(const SomeOtherType& rhs) const {
return x == rhs.value;
}
friend constexpr bool operator==(const SomeOtherType& lhs, const MyCustomType& rhs) {
return lhs.value == rhs.x;
}
constexpr operator MyCustomTypeEqProxy<int>() const { return MyCustomTypeEqProxy<int>(x); }
};
namespace std {
// May not be needed, but allows the custom proxy reference to expand to common references
// of what we're comparing against.
template <typename T, typename U, template <typename> class TQ, template <typename> class UQ>
struct basic_common_reference<::MyCustomTypeEqProxy<T>, U, TQ, UQ> {
using type = ::MyCustomTypeEqProxy< std::common_reference_t<T, UQ<U>> >;
};
template <typename T, typename U, template <typename> class TQ, template <typename> class UQ>
struct basic_common_reference<T, ::MyCustomTypeEqProxy<U>, TQ, UQ> {
using type = ::MyCustomTypeEqProxy< std::common_reference_t<TQ<T>, U> >;
};
// Tell std::common_reference_t about MyCustomTypeEqProxy
template <template <typename> class LQ, template <typename> class RQ>
struct basic_common_reference<::MyCustomType, ::SomeOtherType, LQ, RQ> {
using type = ::MyCustomTypeEqProxy<int>;
};
template <template <typename> class LQ, template <typename> class RQ>
struct basic_common_reference<::SomeOtherType, ::MyCustomType, LQ, RQ> {
using type = ::MyCustomTypeEqProxy<int>;
};
}
我怀疑我错过了一些细微差别,但这足以满足 std :: equality_comparable_with
.
I suspect that I missed some nuances, but this is enough to meet std::equality_comparable_with
.
这篇关于如何告诉编译器MyCustomType与SomeOtherType是equal_comparable_with?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!