英文:
What is a concrete use case of std::ranges::partial_sort_copy with *different* projections?
问题
我找出了我的代码中std::ranges::partial_sort_copy
中的投影不匹配的问题。在阅读了cppreference之后,我无法想象出需要proj1
和proj2
不同的合法情况。
这个算法提供两个不同投影的动机是什么?
英文:
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 <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
// 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 << view << '\n';
}
}
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 = []<typename T>(const T& x) {
// note: in this specific case, we don'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<T, std::string>) {
return x.length();
}
else {
return x.length();
}
};
However, providing two separate projections is often more concise.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论