通用代码中的常量和比较概念
Constness and comparison concepts in generic code
正在看cppreference
template<class T, class U, class Cat = std::partial_ordering>
concept three_way_comparable_with =
std::three_way_comparable<T, Cat> &&
std::three_way_comparable<U, Cat> &&
std::common_reference_with<
const std::remove_reference_t<T>&,
const std::remove_reference_t<U>&> &&
std::three_way_comparable<
std::common_reference_t<
const std::remove_reference_t<T>&,
const std::remove_reference_t<U>&>, Cat> &&
__WeaklyEqualityComparableWith<T, U> &&
__PartiallyOrderedWith<T, U> &&
requires(const std::remove_reference_t<T>& t,
const std::remove_reference_t<U>& u) {
{ t <=> u } -> __ComparesAs<Cat>;
{ u <=> t } -> __ComparesAs<Cat>;
};
在所有的比较概念中,操作数(这里的t
和u
)总是const限定的引用。
这意味着如果我有一个“非正统”class
struct S {
int i;
auto operator<=>(const S&) const = default;
void* operator<=>(S&) = delete;
};
然后 S
模型 std::three_way_comparable
但以下失败
S a, b;
a <=> b;
这是否意味着我必须在 any generic code 中强制执行常量比较?
template<typename T, typename U>
requires std::three_way_comparable_with<T, U>
auto foo(T&& t, U&& u)
{
// if(t <=> u > 0) // wrong!
if(static_cast<const std::remove_reference_t<T>&>(t) <=>
static_cast<const std::remove_reference_t<U>&>(u) > 0)
return bar(std::forward<T>(t));
else
return baz(std::forward<U>(u));
}
正如@StoryTeller 在评论中所暗示的那样:
根据[concepts.equality]/6中的“隐式表达式变体”,因为表达式t <=> u
是non-modifying(操作数是const
左值引用),期望非 const
左值引用而不是 const
左值引用的表达式的变体也是隐式需要的。但是,未指定这些要求是否得到验证。
我没有看到 [cmp.concept] 中 std::three_way_comparable_with
的此规则有任何例外。
您的类型 S
违反了此附加要求,因为变体
requires(std::remove_reference_t<T>& t,
std::remove_reference_t<U>& u) {
{ t <=> u } -> __ComparesAs<Cat>;
{ u <=> t } -> __ComparesAs<Cat>;
};
不满意。因此它不对 std::three_way_comparable_with
.
建模
引用的子句下还有一个very similar example。
正在看cppreference
template<class T, class U, class Cat = std::partial_ordering>
concept three_way_comparable_with =
std::three_way_comparable<T, Cat> &&
std::three_way_comparable<U, Cat> &&
std::common_reference_with<
const std::remove_reference_t<T>&,
const std::remove_reference_t<U>&> &&
std::three_way_comparable<
std::common_reference_t<
const std::remove_reference_t<T>&,
const std::remove_reference_t<U>&>, Cat> &&
__WeaklyEqualityComparableWith<T, U> &&
__PartiallyOrderedWith<T, U> &&
requires(const std::remove_reference_t<T>& t,
const std::remove_reference_t<U>& u) {
{ t <=> u } -> __ComparesAs<Cat>;
{ u <=> t } -> __ComparesAs<Cat>;
};
在所有的比较概念中,操作数(这里的t
和u
)总是const限定的引用。
这意味着如果我有一个“非正统”class
struct S {
int i;
auto operator<=>(const S&) const = default;
void* operator<=>(S&) = delete;
};
然后 S
模型 std::three_way_comparable
但以下失败
S a, b;
a <=> b;
这是否意味着我必须在 any generic code 中强制执行常量比较?
template<typename T, typename U>
requires std::three_way_comparable_with<T, U>
auto foo(T&& t, U&& u)
{
// if(t <=> u > 0) // wrong!
if(static_cast<const std::remove_reference_t<T>&>(t) <=>
static_cast<const std::remove_reference_t<U>&>(u) > 0)
return bar(std::forward<T>(t));
else
return baz(std::forward<U>(u));
}
正如@StoryTeller 在评论中所暗示的那样:
根据[concepts.equality]/6中的“隐式表达式变体”,因为表达式t <=> u
是non-modifying(操作数是const
左值引用),期望非 const
左值引用而不是 const
左值引用的表达式的变体也是隐式需要的。但是,未指定这些要求是否得到验证。
我没有看到 [cmp.concept] 中 std::three_way_comparable_with
的此规则有任何例外。
您的类型 S
违反了此附加要求,因为变体
requires(std::remove_reference_t<T>& t,
std::remove_reference_t<U>& u) {
{ t <=> u } -> __ComparesAs<Cat>;
{ u <=> t } -> __ComparesAs<Cat>;
};
不满意。因此它不对 std::three_way_comparable_with
.
引用的子句下还有一个very similar example。