生成器在 C++20 视图管道中调用两次 [重复]

2023-11-26

在一个简单的管道中views适配器,有gen调用函数来生成一系列值(使用内部状态),然后对其进行过滤。

令人惊讶和违反直觉的(至少对我来说)是这样的事实:生成器函数在每次迭代中被调用两次,因此对同一过滤器的下一次检查失败(过滤后的值不会在管道中重用)。

您知道这是否是正确的预期行为(以及为什么)?

测试用libstdc++在 GCC 10.3、11.1 和主干中(code) and range-v3与 GCC 和 clang (code).

int main() {
  int n = 0;
  auto gen = [&n]() {
    auto result = ++n;
    std::cout << "Generate [" << result << "]\n";
    return result;
  };

  auto tmp =
      ranges::views::iota(0)
      | ranges::views::transform([gen](auto &&) { return gen(); })
      | ranges::views::filter([](auto &&i) {
          std::cout << "#1 " << i << " " << (i % 2) << "\n";
          return (i % 2) == 1;
        });

  for (auto &&i : tmp | ranges::views::take(1)) {
    std::cout << "#2 " << i << " " << ((i % 2) == 1) << "\n";
    assert(((i % 2) == 1));
  }
}

NB: if gen函数被编写为具有内部状态的可变函数,它无法编译:

  auto gen = [n=0]() mutable {
    auto result = ++n;
    std::cout << "Generate [" << result << "]\n";
    return result;
  };

(而且我知道纯函数更好)


您知道这是否是正确的预期行为(以及为什么)?

是的:这是预期的行为。这是迭代模型的固有属性,我们有operator* and operator++作为单独的操作。

filter's operator++必须寻找下一个满足谓词的底层迭代器。这涉及到做*it on transform的迭代器涉及调用该函数。但是一旦我们找到下一个迭代器,当我们再次读取它时,就会再次调用转换。在代码片段中:

decltype(auto) transform_view<V, F>::iterator::operator*() const {
    return invoke(f_, *it_);
}

decltype(auto) filter_view<V, P>::iterator::operator*() const {
    // reading through the filter iterator just reads
    // through the underlying iterator, which in this
    // case means invoking the function
    return *it_;
}

auto filter_view<V, P>::iterator::operator++() -> iterator& {
    for (++it_; it_ != ranges::end(parent_->base_); ++it_) {
        // when we eventually find an iterator that satisfies this
        // predicate, we will have needed to read it (which calls
        // the functions) and then the next operator* will do
        // that same thing again
        if (invoke(parent_->pred_, *it_))) {
            break;
        }
    }
    return *this;
}

结果是我们对满足谓词的每个元素调用该函数两次。


解决方法是要么不关心(让转换足够便宜,调用它两次并不重要,或者过滤器足够稀有,使得重复转换的数量无关紧要,或者两者兼而有之),或者添加一个缓存层你的管道。

C++20 Ranges 中没有缓存视图,但 range-v3 中有一个名为views::cache1:

ranges::views::iota(0)
    | ranges::views::transform(f)
    | ranges::views::cache1
    | ranges::views::filter(g)

这确保了f每个元素最多只被调用一次,代价是必须处理元素缓存并将范围降级为仅输入范围(之前是双向的)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

生成器在 C++20 视图管道中调用两次 [重复] 的相关文章

  • Unity3D StartCoroutine 调用一个函数,该函数什么时候返回?

    我知道Unity3D StartCoroutine调用了一个与StartCoroutine在同一线程上运行的函数 但是被调用的函数什么时候返回到原始调用者 我在互联网上查找了一个很好的 Unity3D Coroutine 示例 但找不到完整
  • C 中的变量定义是什么意思[重复]

    这个问题在这里已经有答案了 你们能告诉我 这在 C 中意味着什么吗 define Privileged Data Privileged Data static int dVariable 编译器对变量进行寻址有特殊意义吗 这只是一个宏Pri
  • SetWindowsHookEx 函数返回 NULL

    我正在研究 DLL 注入 但收到错误如下 挂接进程失败 87 参数不正确 目标进程和dll都是64位的 注入代码为 BOOL HookInjection TCHAR target TCHAR dll name https msdn micr
  • WebClient读取错误页面的内容

    我有一个加载页面内容的应用程序 我使用 WebClient 类 即使服务器返回 404 500 等错误 我也需要检索内容 我需要这样的东西 WebClient wc new WebClient string pageContent try
  • C# 中的协变和逆变

    首先我要说的是 我是一名正在学习 C 编程的 Java 开发人员 因此 我会将我所知道的与我正在学习的进行比较 我已经使用 C 泛型几个小时了 我已经能够在 C 中重现我在 Java 中知道的相同内容 除了几个使用协变和逆变的示例 我正在读
  • 为什么派生类不使用基类的operator=(赋值运算符)?

    以下是实际问题的简化版本 而不是打电话Base operator int 代码似乎生成了一个临时的Derived对象并复制它 既然函数签名似乎完美匹配 为什么不使用基本赋值运算符 这个简化的示例没有显示任何不良影响 但原始代码在析构函数中有
  • 返回 int& 的函数[重复]

    这个问题在这里已经有答案了 我在网上查了一下发现一篇试图解释的文章std move和右值 http thbecker net articles rvalue references section 01 html并发现了一些我实在无法掌握的东
  • 关闭 XDOCUMENT 的实例

    我收到这个错误 该进程无法访问文件 C test Person xml 因为它是 被另一个进程使用 IOException 未处理 保存文件内容后如何关闭 xml 文件的实例 using System using System Collec
  • F10键没被抓住

    I have a Windows Form and there overriden ProcessCmdKey However this works with all of the F Keys except for F10 I am tr
  • C 中的模仿函数重写

    具体来说 函数重写能够调用基本重写方法 这有两部分 一个是预编译的库代码 1 另一个是库的用户代码 2 我在这里实现了一个尽可能最小的经典 Person 和 Employee 示例 非常感谢了解 OOP 概念的铁杆 C 开发人员的回应 我正
  • .net Framework (.net 4.0) 中定义 Base 3 数字的类

    我正在寻找一些可以用来定义 3 基数 三进制数 的类 有什么我可以在 net 框架中使用的东西或者我需要写一些东西吗 谢谢你的帮助 您可以使用解析Convert ToInt32 s base http msdn microsoft com
  • 使用 openssl 检查服务器安全协议

    我有一个框架应用程序 它根据使用方式连接到不同的服务器 对于 https 连接 使用 openssl 我的问题是 我需要知道我连接的服务器是否使用 SSL 还是 TLS 以便我可以创建正确的 SSL 上下文 目前 如果我使用错误的上下文尝试
  • 抽象类或接口。哪种方式是正确的?

    有两种方法可以选择抽象类或接口 微软解决方案和Oracle解决方案 微软 设计指南 请使用抽象 在 Visual Basic 中为 MustInherit 类而不是接口来将协定与实现分离 http msdn microsoft com en
  • 在“using”语句中使用各种类型 (C#)

    自从C usingstatements只是try finally dispose 的语法糖 为什么它接受多个对象仅当它们属于同一类型时 我不明白 因为它们需要的只是 IDisposable 如果它们都实现 IDisposable 应该没问题
  • C# 中处理 SQL 死锁的模式?

    我正在用 C 编写一个访问 SQL Server 2005 数据库的应用程序 该应用程序是数据库密集型的 即使我尝试优化所有访问 设置适当的索引等 我预计迟早会遇到死锁 我知道为什么会发生数据库死锁 但我怀疑我能否在某个时候发布不发生死锁的
  • 如何将字符串转换为 Indian Money 格式?

    我正在尝试将字符串转换为印度货币格式 例如如果输入为 1234567 则输出应为 12 34 567 我编写了以下代码 但它没有给出预期的输出 CultureInfo hindi new CultureInfo hi IN string t
  • Dynamics Crm:获取状态代码/状态代码映射的元数据

    在 Dynamics CRM 2011 中 在事件实体上 状态原因 选项集 也称为状态代码 与 状态 选项集 也称为状态代码 相关 例如看这个截图 当我使用 API 检索状态原因选项集时 如下所示 RetrieveAttributeRequ
  • 将 bignum 类型结构转换为人类可读字符串的有效方法是什么?

    我有一点问题 为了增长我的 C 知识 我决定尝试实现一个基本的 bigint 库 bigint 结构的核心将是一个 32 位整数数组 选择它们是因为它们适合寄存器 这将允许我在数字之间进行操作 这些操作将在 64 位整数中溢出 这也将适合寄
  • 在何处将 CFLAG(例如 -std=gnu99)添加到 (Eclipse CDT) 自动工具项目中

    我有一个简单的 Autotools C 项目 不是 C 其框架是由 Eclipse CDT Juno 为我创建的 CFLAG 通过检查 似乎是 g O2 我希望所有生成的 make 文件也具有 std gnu99附加到 CFLAG 因为我使
  • 将文本从文本文件添加到 PDF 文件[重复]

    这个问题在这里已经有答案了 这是我的代码 using FileStream msReport new FileStream pdfPath FileMode Create step 1 using Document pdfDoc new D

随机推荐

  • 从本地主机连接到在线 MySQL 数据库

    我正在尝试通过本地主机上的 PHP 连接到在线服务器上的 MySQL 数据库 con mysql connect hostname username password if con die Could not connect mysql e
  • 在 中执行 JavaScript,getElementById 返回 null

    我有以下代码 div div 有谁知道为什么x null It s null因为您在 DOM 加载之前调用脚本 将脚本包装在将被调用的函数中onload
  • 从父承诺中解决一系列承诺

    这是我第一次尝试嵌套承诺 我正在使用bluebird库 但我认为所有承诺库的想法都是相同的 从高层次来看 这就是我正在尝试做的事情 myService getSomeData url then data gt myOtherService
  • 用另一个数据帧的值替换一个数据帧中的列值

    我有两个数据框 第一个有 1000 行 看起来像 Date Group Family Bonus 2011 06 09 tri23 1 Laavin 456 2011 07 09 hsg T2 Grendy 679 2011 09 10 b
  • 如何从 mysql 查询运行 python 脚本?

    我希望从 mysql 查询中调用 python 脚本 就像我们在 mysql 中调用过程一样 call procedurename 就像上面一样 mysql 有没有办法调用外部脚本 例如 call script somefile py 我写
  • Android 中的裁剪图片

    我已经尝试这个有一段时间了 我想从Bitmap 假设所需的壁纸尺寸为 320x480 源图像尺寸为 2048x2048 我不确定 裁剪适合 是否是正确的术语 但我想要实现的是获得与所需壁纸尺寸 320x480 具有相同比例的图片的大部分 所
  • XML 文档到字符串

    获取 XML 文档的字符串表示形式的最简单方法是什么 org w3c dom Document 也就是说 所有节点都将位于一条线上 举个例子 从
  • 如何制作圆形遮罩和剪辑GLSurfaceView?

    我使用的 SDK 提供了一个矩形GLSurfaceView通过回调 我希望能够以圆形布局渲染此视图 即 我想在圆形视图上显示视图 当我叠加时它显示圆形GLSurfaceView over ImageView GLSurfaceView ov
  • Nodejs 向带有 .p12 证书的 Web 服务发出请求

    所以 标题非常简单 我想使用一家公司的 Web 服务 并且我获得了 cer 和 p12 文件 据说 我在发出请求时应该使用 p12 我已经将 cer 导入到 Windows 中 我可以轻松地使用邮递员发出请求 但是当我尝试使用 node j
  • 如何区分鼠标滚动和 JavaScript 中以编程方式滚动?

    我通过更改滚动溢出的 DIV 内容scrollLeftJavaScript 中的属性 setInterval function scrollbox scrollLeft scrollbox scrollLeft 1 50 但是 我想在用户使
  • OpenCV Mat 数据成员访问

    我见过很多 OpenCV 代码 它们访问 a 的数据成员cv Mat直接地 cv Mat将指向数据的指针存储在unsigned char data成员 对数据成员的访问如下所示 cv Mat matUC 3 3 CV 8U int rowI
  • 作为参数传递时,Java 后自增 (++) 的行为不符合预期

    我遇到了以下问题 private void doStuff int i if i gt 10 return doStuff i public void publicMethod doStuff i 我希望这能运行doStuff10次 然后返
  • 如何在Python中保存和恢复多个变量?

    我需要将大约十几个对象保存到一个文件中 然后稍后恢复它们 我尝试将 for 循环与 pickle 和 shelve 一起使用 但效果不佳 Edit 我试图保存的所有对象都在同一个类中 我应该之前提到过这一点 并且我没有意识到我可以像这样保存
  • 如何在不加载 .dll 的情况下读取程序集清单

    本质上需要以编程方式读取依赖项 而不加载程序集本身 因为这样您就无法卸载它们 找到了这个 System Reflection Assembly ReflectionOnlyLoadFrom 路径 成功了
  • MSBuild OutputPath 属性和绝对路径

    我试图将 OutputPath 值设置为绝对路径
  • 单词中的序数 javascript

    有没有什么优雅的方法可以在js coffee中获取word格式的序数 像这样的东西 ordinalInWord 1 gt first ordinalInWord 2 gt second ordinalInWord 5 gt fifth 恐怕
  • FFMPEG 解码太慢(avcodec_send_packet() / avcodec_receive_frame())

    我正在使用 ffmpeg 库对 MPEG 传输流中的视频进行解码 缩放和重新编码 我刚刚从源代码重新编译到 v3 3 2 并从旧的 avcodec decode video2 API 更改为新的发送 接收 API 新旧 API 解码视频的速
  • 如何解决 Windows 上的文件夹与 Git 的大小写冲突?

    我正在做一个git rebase 我被困住了 因为在一次提交中我有一个名为Proto 但在另一个提交中我有一个名为的文件夹proto 这是一个无心的错误 应该是Proto在这两种情况下 我在这里能想到的最好方法是尝试从两次提交中删除该文件夹
  • 如何从Mac上完全卸载symfony和composer

    我想从我的 Mac 上完全删除 symfony 和composer 我已经用谷歌搜索了五个小时 但没有找到关于如何从我的 Mac 上完全卸载 Composer 和 symfony 的文档 为什么这么难找 甚至在 Symfony 网站上 您计
  • 生成器在 C++20 视图管道中调用两次 [重复]

    这个问题在这里已经有答案了 在一个简单的管道中views适配器 有gen调用函数来生成一系列值 使用内部状态 然后对其进行过滤 令人惊讶和违反直觉的 至少对我来说 是这样的事实 生成器函数在每次迭代中被调用两次 因此对同一过滤器的下一次检查