c++ - 无法使用 std::ranges::copy_if(R&& r, O result, Pred pred, Proj proj = {}) 编译我的示例

标签 c++ algorithm c++20 std-ranges

我已经将无法编译的代码减少为以下代码:

[Demo]

#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/

相关文章:

c++ - Makefile 找不到 macports 安装的 boost 库

c++ - OPENCV 错误 : undefined reference to "cvLoadImage"

c++ - 使用 if else 语句的函数将数字从大到小排序

c++ - 查找数组中最大数的有效方法

template-specialization - 为什么概念类模板特化会导致错误

java - 在 Java OpenCV 中替换像素的等效代码

c++ - 如何预测 Base32 解码输出所需的大小?

algorithm - 用于保存和检索平面中的点的数据结构

c++ - lambda 可以用作非类型模板参数吗?

c++ - 如何在自定义容器中支持范围适配器?