如何使 range::binary_search (特别是异构搜索)与引用一起使用

Vir*_*leo 2 c++ c++20 std-ranges

我正在尝试使引用包装器与异构搜索一起使用,并使其符合范围。这是我想要工作的片段:

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
}
Run Code Online (Sandbox Code Playgroud)

异构搜索对于经典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;
    }

    // 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; }
};
Run Code Online (Sandbox Code Playgroud)

然而,这会导致许多编译错误,这些错误似乎是在警告indirect_strict_weak_order概念strict_weak_order未得到解决。我不明白为什么他们没有解决 - 我们有很强的秩序,并且据我了解,间接部分得到了适当的支持。我缺少什么?

这是编译器资源管理器示例:https ://godbolt.org/z/8xaWfah9b 。

康桓瑋*_*康桓瑋 6

异构搜索对于经典std算法来说工作得很好(对于它们来说,实现<和就足够了==。现在,ranges人们有更严格的要求

version默认用于比较,它对比较类型的语法和语义要求比rangesversion更严格,但您仍然可以作为仅要求表达式有效的比较器传递ranges::lessstdstd::lesslhs < rhs

const auto found = ra::binary_search(num_refs, 2, std::less{});
Run Code Online (Sandbox Code Playgroud)

演示


Art*_*yer 5

范围算法不适用于异构比较。使用投影:

std::ranges::binary_search(num_refs, 2, {}, [](ref<const addressable> r) {
    return r.get().address;
});
Run Code Online (Sandbox Code Playgroud)

在这种特定情况下,您不能使用ranges::less{}(2, ref<const addressable>(...)),因为ranges::less需要两个参数totally_ordered彼此在一起,这要求它们有一个common_reference. const int&和之间没有公共引用,除非您添加从到 的const ref<const addressable>&转换。ref<const addressable>const int&