英文:
How to make ranges::binary_search (heterogeneous search in particualar) work with references
问题
我正在尝试使引用包装器与异构搜索一起工作,并使其符合范围要求。这是我想要工作的代码段:
struct addressable { int address; };
template <typename T>
struct ref : std::reference_wrapper<T> {
// 用于异构搜索的比较操作
}
template <typename T>
ref<T> wrap_ref(T& value) { return {value}; }
int main() {
const std::vector<addressable> nums { {1}, {2}, {3}, {4}, {5}, {6} };
ref_vec<const addressable> num_refs;
for (const auto& num : nums) { num_refs.push_back(wrap_ref(num)); }
const auto found = std::ranges::binary_search(num_refs, 2); // 不起作用
}
对于经典的 std
算法,异构搜索正常工作(对于它们来说,实现 <
和 ==
就足够了)。现在,ranges
的算法有更严格的要求,所以我尝试以以下方式实现强制排序操作:
template <typename T>
struct ref : std::reference_wrapper<T> {
auto operator<=>(const ref<T>& other) const {
return std::reference_wrapper<T>::get().address <=> other.get().address;
}
bool operator==(const ref<T>& other) const {
return std::reference_wrapper<T>::get().address == other.get().address;
}
// 异构比较
friend auto operator<=>(const ref<T>& l, const int r) { return l.get().address <=> r; }
friend auto operator<=>(const int l, const ref<T>& r) { return l <=> r.get().address; }
friend bool operator==(const ref<T>& l, const int r) { return l.get().address == r; }
friend bool operator==(const int l, const ref<T>& r) { return l == r.get().address; }
};
然而,这导致了一系列编译错误,似乎在警告 indirect_strict_weak_order
和 strict_weak_order
概念未被解析。我不明白为什么它们没有被解析 - 我们有强序,并且据我了解,引用在间接部分上得到了适当的支持。我漏掉了什么?
这里是编译器探索器的示例链接:https://godbolt.org/z/8xaWfah9b。
英文:
I am trying to make reference wrappers work with heterogeneous search, and make it ranges-compliant. Here is the snippet I want to work:
struct addressable { int address; };
template <typename T>
struct ref : std::reference_wrapper<T> {
// comparisons for heterogeneous search
}
template <typename T>
ref<T> wrap_ref(T& value) { return {value}; }
int main() {
const std::vector<addressable> nums { {1}, {2}, {3}, {4}, {5}, {6} };
ref_vec<const addressable> num_refs;
for (const auto& num : nums) { num_refs.push_back(wrap_ref(num)); }
const auto found = std::ranges::binary_search(num_refs, 2); // doesn't work
}
The heterogeneous search is working fine for classic std
algorithms (for them it is enough to implement <
and ==
. Now, ranges
ones have more stringent requirements, so I tried implementing strong ordering operations in the following manner:
template <typename T>
struct ref : std::reference_wrapper<T> {
auto operator<=>(const ref<T>& other) const {
return std::reference_wrapper<T>::get().address <=> other.get().address;
}
bool operator==(const ref<T>& other) const {
return std::reference_wrapper<T>::get().address == other.get().address;
}
// heterogeneous comparisons
friend auto operator<=>(const ref<T>& l, const int r) { return l.get().address <=> r; }
friend auto operator<=>(const int l, const ref<T>& r) { return l <=> r.get().address; }
friend bool operator==(const ref<T>& l, const int r) { return l.get().address == r; }
friend bool operator==(const int l, const ref<T>& r) { return l == r.get().address; }
};
This, however, leads to a number of compilation errors, which seem to warn about indirect_strict_weak_order
and strict_weak_order
concepts not being resolved. I do not understand why aren't they resolved - we have strong order, and references are, to my understanding, properly supported for the indirect part. What am I missing?
Here is compiler explorer example: https://godbolt.org/z/8xaWfah9b.
答案1
得分: 6
Sure, here's the translated content:
异构搜索对经典的
std
算法工作良好(对它们来说,只需实现<
和==
就足够了)。现在,ranges
版本具有更严格的要求。
ranges
版本默认使用 ranges::less
进行比较,它对比较类型有比 std
版本更严格的语法和语义要求,但您仍然可以将 std::less
作为比较器传递,它只要求表达式 lhs < rhs
有效即可。
const auto found = ra::binary_search(num_refs, 2, std::less{});
英文:
> The heterogeneous search is working fine for classic std
algorithms
> (for them it is enough to implement <
and ==
. Now, ranges
ones have
> more stringent requirements
The ranges
version uses ranges::less
for comparison by default, which has stricter syntactic and semantic requirements for comparison types than the std
version, but you can still pass std::less
as a comparator that only requires expressions lhs < rhs
to be valid
const auto found = ra::binary_search(num_refs, 2, std::less{});
答案2
得分: 5
Ranges算法不支持异构比较。请使用投影:
std::ranges::binary_search(num_refs, 2, {}, [](ref<const addressable> r) {
return r.get().address;
});
在这种特定情况下,您不能使用 ranges::less{}(2, ref<const addressable>(...))
,因为ranges::less
要求两个参数在彼此之间是totally_ordered
,这要求它们具有common_reference
。在const int&
和const ref<const addressable>&
之间没有共同的引用,除非您添加从ref<const addressable>
到const int&
的转换。
英文:
Ranges algorithms don't work with heterogenous comparisons. Use a projection:
std::ranges::binary_search(num_refs, 2, {}, [](ref<const addressable> r) {
return r.get().address;
});
In this specific case, you can't use ranges::less{}(2, ref<const addressable>(...))
, because ranges::less
requires the two arguments to be totally_ordered
with each other, which requires them to have a common_reference
. There is no common reference between const int&
and const ref<const addressable>&
, unless you add a conversion from ref<const addressable>
to const int&
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论