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

huangapple go评论134阅读模式
英文:

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_orderstrict_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 &lt;typename T&gt;
struct ref : std::reference_wrapper&lt;T&gt; {
    // comparisons for heterogeneous search
}

template &lt;typename T&gt;
ref&lt;T&gt; wrap_ref(T&amp; value) { return {value}; }

int main() {
    const std::vector&lt;addressable&gt; nums { {1}, {2}, {3}, {4}, {5}, {6} };
    ref_vec&lt;const addressable&gt; num_refs;
    for (const auto&amp; num : nums) { num_refs.push_back(wrap_ref(num)); }
    const auto found = std::ranges::binary_search(num_refs, 2); // doesn&#39;t work
}

The heterogeneous search is working fine for classic std algorithms (for them it is enough to implement &lt; and ==. Now, ranges ones have more stringent requirements, so I tried implementing strong ordering operations in the following manner:

template &lt;typename T&gt;
struct ref : std::reference_wrapper&lt;T&gt; {
    auto operator&lt;=&gt;(const ref&lt;T&gt;&amp; other) const {
        return std::reference_wrapper&lt;T&gt;::get().address &lt;=&gt; other.get().address;
    }
    
    bool operator==(const ref&lt;T&gt;&amp; other) const {
        return std::reference_wrapper&lt;T&gt;::get().address == other.get().address;
    }

    // heterogeneous comparisons
    friend auto operator&lt;=&gt;(const ref&lt;T&gt;&amp; l, const int r) { return l.get().address &lt;=&gt; r; }
    friend auto operator&lt;=&gt;(const int l, const ref&lt;T&gt;&amp; r) { return l &lt;=&gt; r.get().address; }
    friend bool operator==(const ref&lt;T&gt;&amp; l, const int r) { return l.get().address == r; }
    friend bool operator==(const int l, const ref&lt;T&gt;&amp; 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 &lt; 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 &lt; rhs to be valid

const auto found = ra::binary_search(num_refs, 2, std::less{});

Demo

答案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&lt;const addressable&gt; r) {
    return r.get().address;
});

In this specific case, you can't use ranges::less{}(2, ref&lt;const addressable&gt;(...)), 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&amp; and const ref&lt;const addressable&gt;&amp;, unless you add a conversion from ref&lt;const addressable&gt; to const int&amp;.

huangapple
  • 本文由 发表于 2023年7月3日 04:57:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76600767.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定