我已经将无法编译的代码减少为以下代码:
#include <algorithm> // copy_if
#include <iostream> // cout
#include <iterator> // back_inserter
#include <ranges>
#include <string>
#include <vector>
struct A
{
std::string p{};
std::string d{};
};
int main()
{
std::vector<A> v{{"/usr/bin/cat", "blah"}, {"/usr/lib", "foo"}};
std::vector<std::string> o{};
std::ranges::copy_if(
v,
std::back_inserter(o),
[](std::string& p){ return (p.size() > 10); },
&A::p);
}
Visual Studio 的错误输出很短:error C7602: 'std::ranges::_Copy_if_fn::operator ()': the associated constraints are not satisfied.
它基本上会指示您检查 copy_if
的约束在 algorithm
标题。
gcc 和 clang 比较详细。看一下两个输出:
- 首先,
copy_if
考虑范围、输出迭代器、谓词和投影的重载。 - 但是,表达式
*__o = (std::forward<_Tp>(__t)
被评估为无效;其中:'_Out&& __o', '_Tp&& __t' [with _Tp = A&; _Out = std::back_insert_iterator<std::vector<std::string>>]
因为我们使用的是投影(从 A&
到 std::string&
),为什么要复制一个 A&
而不是 std::string&
至 o
?
完整的错误输出可通过上面的演示链接访问。
最佳答案
投影仅适用于谓词,不适用于结果。已经有一种方法可以完全转换数据— std::views::transform
:
std::ranges::copy_if(
v | std::views::transform(&A::p),
std::back_inserter(o),
[](const std::string& p){ return (p.size() > 10); });
(这可以在 GCC 和 MSVC 中编译,但不能在 Clang 中编译。我不是 100% 有信心说它是正确的,但如果没有别的,它应该是接近的,它说明了这一点。)
投影适用于您想要测试数据的转换(投影),同时携带原始数据。在此示例中,这意味着您将输出到 std::vector<A>
, 测试 std::string
在谓词中。在这里不是很有用,因为你可以 return (a.p.size() > 10);
, 但如果传递预先编写的函数而不是使用 lambda 则很有用。对于其他一些情况也很有用,例如按成员轻松排序——只需使用默认比较器并传递 &A::p
作为投影。
关于c++ - 无法使用 std::ranges::copy_if(R&& r, O result, Pred pred, Proj proj = {}) 编译我的示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71042923/