std::ranges::partial_sort_copy具有*不同*投影的一个具体用例是什么?

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

What is a concrete use case of std::ranges::partial_sort_copy with *different* projections?

问题

我找出了我的代码中std::ranges::partial_sort_copy中的投影不匹配的问题。在阅读了cppreference之后,我无法想象出需要proj1proj2不同的合法情况。

这个算法提供两个不同投影的动机是什么?

英文:

I root caused a problem in my code to mismatched projections in std::ranges::partial_sort_copy. After reading cppreference, I couldn't think of a legitimate situation where proj1 & proj2 needed to be different.

What's the motivation for this algorithm providing two different projections?

答案1

得分: 3

以下是翻译好的部分:

当输入范围的类型与输出范围的类型不匹配时,您需要它。

考虑以下示例:

#include <string>
#include <ranges>
#include <algorithm>
#include <iostream>

int main() {
    std::string names[] = {
        "alpha",
        "beta",
        "tau",
        "pi",
        "omega"
    };
    std::string_view shortest_three[3];

    std::ranges::partial_sort_copy(names, shortest_three,
                                   {},                         // std::ranges::less 
                                   &std::string::length,       // proj1
                                   &std::string_view::length); // proj2
    // 注意:在 std::string/std::string_view 中可能不允许获取成员函数的地址。
    // (未指定的行为,请参见 [namespace.std]/6)
    // 为了安全起见,我们应该将对 length() 的访问包装在 lambda 表达式中。

    for (auto view : shortest_three) {
        std::cout << view << '\n';
    }
}

这将输出:

pi
tau
beta

在此示例中,如果目标范围包含 std::string 对象,将是浪费的,因为我们可以将最短的三个字符串存储为 const char*std::string_view。因此,这里应用了两个不同的投影。

从技术上讲,您总是可以创建一个涵盖两种情况的单一投影:

auto proj = []<typename T>(const T& x) {
    // 注意:在这种特定情况下,我们不需要此 if 语句,
    // 因为成员函数的名称对于两种类型都是完全相同的。但是,这可能并不总是如此,
    // 例如,对于一种类型我们需要 .length(),而对于另一种类型我们需要 .size()。
    if constexpr (std::is_same_v<T, std::string>) {
        return x.length();
    }
    else {
        return x.length();
    }
};

但是,通常提供两个单独的投影更加简洁。

英文:

You need it when there is a mismatch between the type of the input range, and the type of the output range.
Consider the following example:

#include &lt;string&gt;
#include &lt;ranges&gt;
#include &lt;algorithm&gt;
#include &lt;iostream&gt;

int main() {
    std::string names[] = {
        &quot;alpha&quot;,
        &quot;beta&quot;,
        &quot;tau&quot;,
        &quot;pi&quot;,
        &quot;omega&quot;
    };
    std::string_view shortest_three[3];

    std::ranges::partial_sort_copy(names, shortest_three,
                                   {},                         // std::ranges::less 
                                   &amp;std::string::length,       // proj1
                                   &amp;std::string_view::length); // proj2
    // note: It might not be allowed to take the address of
    //       member functions in std::string/std::string_view.
    //       (unspecified behavior, see [namespace.std]/6)
    //       To be on the safe side, we would have to wrap access to length()
    //       in a lambda expression.

    for (auto view : shortest_three) {
        std::cout &lt;&lt; view &lt;&lt; &#39;\n&#39;;
    }
}

This outputs:

pi
tau
beta

In this example, it would be wasteful if the destination range contained std::string objects, because we could just as well store the shortest three strings as a const char* or std::string_view.
As a result, there are two different projections applied here.

Technically you could always create a single projection that covers both cases:

auto proj = []&lt;typename T&gt;(const T&amp; x) {
    // note: in this specific case, we don&#39;t need this if-statement,
    //       because the name of the member function is the exact same for
    //       both types. However, this may not always be the case, e.g.
    //       we need .length() for one type and .size() for another.
    if constexpr (std::is_same_v&lt;T, std::string&gt;) {
        return x.length();
    }
    else {
        return x.length();
    }
};

However, providing two separate projections is often more concise.

huangapple
  • 本文由 发表于 2023年6月21日 23:03:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76524706.html
匿名

发表评论

匿名网友

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

确定