如何解决C++ 安全有效地将 std::weak_ordering 转换为 int
C++20 引入了一种新的比较类型:std::weak_ordering。
它允许表示小于、等于或大于。
但是,一些较旧的函数使用 int
用于类似目的。如qsort,使用签名
int compar (const void* p1,const void* p2);
如何将 std::weak_ordering
转换为 int
以便在 qsort
等函数中使用?
这是一个示例情况:
#include <compare>
#include <iostream>
int main() {
long a = 2354,b = 1234;
std::weak_ordering cmp = a <=> b;
if (cmp > 0) std::cout << "a is greater than b" << std::endl;
if (cmp == 0) std::cout << "a is equal to b" << std::endl;
if (cmp < 0) std::cout << "a is less than b" << std::endl;
int equivalent_cmp = cmp; // errors
}
在测试中,我注意到使用 reinterpret_cast
到 int8_t
类型确实有效,但我不确定这是否可移植。
int equivalent_cmp = *(int8_t *)&cmp;
或等效地,
int equivalent_cmp = *reinterpret_cast<int8_t*>(&cmp);
这样安全吗?
此外,还有一些其他解决方案可以工作,但与这种“不安全”的方法相比效率低下。所有这些都会比上述解决方案慢
int equivalent_cmp = (a > b) - (a < b);
或
int equivalent_cmp;
if (cmp < 0) equivalent_cmp = -1;
else if (cmp == 0) equivalent_cmp = 0;
else equivalent_cmp = 1;
是否有更好的解决方案可以保证有效?
解决方法
是否有更好的解决方案可以保证有效?
没有
该标准没有指定排序类的内容或表示。 Barry 的回答基于合理的假设,这些假设可能成立,但不能保证。
如果你需要它,最好的办法是写一些像你最后一个片段一样的东西
constexpr int ordering_as_int(std::weak_ordering cmp) noexcept {
return (cmp < 0) ? -1 : ((cmp == 0) ? 0 : 1);
}
,
如何将 std::weak_ordering
转换为 int
以便在 qsort
等函数中使用?
简单的答案是:不要使用qsort
,使用std::sort
,它无论如何都会表现得更好。
也就是说,我们知道 std::weak_ordering
必须有一些整数类型成员,而 C++20 确实提供了将其拉出的机制:std::bit_cast
:
static_assert(std::bit_cast<int8_t>(0 <=> 1) == -1);
规则是您要转换到的类型(在本例中为 int8_t
)必须与您要从中进行转换的类型(在本例中为 std::strong_ordering
)的大小相同。这是对 bit_cast
的约束,所以它是安全的 - 如果实现实际上存储的是 int
而不是 int8_t
,这将无法编译。
所以更一般地说,您必须编写一个简短的元程序来确定要强制转换的正确有符号整数类型。
请注意,虽然 weak_ordering
和 strong_ordering
将仅实现为存储整数(尽管不是标准中所示的 int
),但 partial_ordering
可能会不被实现为存储一个 int
和一个 bool
- 它可能仍然被实现为单个整数。所以这个技巧是行不通的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。