Ranges::view::transform 生成一个 InputIterator,防止使用 std::prev

2024-01-11

考虑以下代码,它使用 C++20 中的 Ranges 库:

#include <vector>
#include <ranges>
#include <iostream>

int main()
{
    std::vector<int> v{0,1,2,3,4,5,6,7};

    auto transformed = std::ranges::views::transform(v, [](int i){ return i * i; });

    std::cout << *std::prev(std::end(transformed));
}

我很惊讶地得知(至少在 GCC-10.3.0 和 GCC-12.0.0 下)这段代码陷入困境std::prev https://wandbox.org/permlink/IAOwmkKQlabOP6cu.

发生的情况是,由于 lambda 不返回左值引用,因此transformed范围迭代器被分类为输入迭代器(参见rules https://en.cppreference.com/w/cpp/ranges/transform_view/iterator for iterator_category选择为views::transform)。然而,std::prev requires https://en.cppreference.com/w/cpp/iterator/prev迭代器至少是一个双向迭代器,所以我猜这段代码实际上是UB。在 libstdc++ 中应用std::prev输入迭代器导致此函数

template<typename _InputIterator, typename _Distance>
__advance(_InputIterator& __i, _Distance __n, input_iterator_tag)
{
    // concept requirements
    __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
    __glibcxx_assert(__n >= 0);
    while (__n--)
        ++__i;
}

被称为与__n == -1,这解释了观察到的行为。

如果我们更换std::prev使用手动迭代器递减,一切正常 https://wandbox.org/permlink/t6mMSBOcDFzOTZgt。切换到std::ranges::prev 也有效 https://wandbox.org/permlink/BVWhksNDhVgvQR6H.

现在,这显然是荒谬的,我做不到std::prev关于什么只是一个观点std::vector。虽然存在一个简单的解决方案,但我对标准库的新旧范围操作部分之间这种意外的相互作用感到非常担心。所以,我的问题是:这是一个已知问题吗?我真的应该忘记所有不在其中的内容吗?std::ranges使用新范围时的命名空间,并重写所有现有代码以确保它们适用于新范围?


根据 C++17 的计算,它不是随机访问迭代器。transform必须返回一个值而不是reference,并且 C++17 的迭代器类别不允许对 InputIterator 之上的任何内容进行这种操作。

但这种类型是一个std::random_access_iterator根据 C++20 的规则,它允许在连续以下的任何迭代器/范围上使用类似代理的迭代器。

std::prev是 C++20 之前的工具,因此它按照 C++20 之前的规则工作。如果您需要使用 C++20 规则,则必须使用C++20 等效项:std::ranges::prev https://en.cppreference.com/w/cpp/iterator/ranges/prev.

现在,我不能对 std::vector 的视图执行 std::prev ,这显然是荒谬的。

不,是必要的。 C++20 的概念化迭代器类别比以前的 C++ 版本中的限制更少。这意味着有些迭代器不能在 C++20 之前的代码中使用,can用于 C++20 基于范围的代码中。

这就是为什么我们在ranges命名空间。

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

Ranges::view::transform 生成一个 InputIterator,防止使用 std::prev 的相关文章

  • C++ 有像 Pascal 一样的“with”关键字吗?

    withPascal 中的关键字可用于快速访问记录的字段 有人知道 C 是否有类似的东西吗 前任 我有一个包含许多字段的指针 但我不想这样输入 if pointer gt field1 pointer gt field2 pointer g
  • 何时对向量进行归一化?

    我正在学习 XNA 并且在几乎所有的教育套件中都可以找到http creators xna com en US http creators xna com en US 我总是看到向量上对 Normalize 的调用 我知道归一化基本上将向量
  • C++ - 模板专业化和部分专业化

    我一直在互联网和 stackoverflow 上寻找具体的答案 但我似乎找不到 我必须创建一个通用类 然后实现特定的功能 我的具体说明是 您需要使用模板表达式参数以及模板类专业化和部分专业化 我有一个模板类 template
  • 此插件导致 Outlook 启动缓慢

    我正在使用 C NET 4 5 开发 Outlook Addin 项目 但部署后 有时 Outlook 会禁用我的插件 并显示此消息 这个插件导致 Outlook 启动缓慢 我不知道我的插件出了什么问题 这只有很少的代码 并且ThisAdd
  • 为什么 LinkedList 通常比 List 慢?

    我开始在我的一些 C 算法中使用一些 LinkedList 而不是列表 希望能够加快速度 然而 我注意到他们只是感觉更慢 像任何优秀的开发人员一样 我认为我应该尽职调查并验证我的感受 所以我决定对一些简单的循环进行基准测试 我认为用一些随机
  • C++:获取注册表值仅给出第一个字符[重复]

    这个问题在这里已经有答案了 我试图从注册表中获取字符串值 但我只得到第一个字母 HKEY hKey char gamePath MAX PATH if RegOpenKeyEx HKEY CURRENT USER L Software Bl
  • 隐形打开的弹出窗口

    第二天就解决这个问题 要重现 请创建新的 WPF 应用程序 xaml
  • 如何在 C++ 的子目录中创建文件?

    这是我的代码 如何在子目录联系人中创建文件 每次创建该文件时 它都会出现在与我的程序相同的目录中 int main ofstream myfile contacts myfile open a myfile close 在构造函数中指定完整
  • CMake 警告:无法为目标生成安全的链接器搜索路径

    在为 pcl 项目运行 CMake 时 我收到一条警告消息 Configuring done CMake Warning at CMakeLists txt 12 add executable Cannot generate a safe
  • C++ 模板参数类型推断

    我有一个这样的C 模板 template
  • 未定义异常变量时通过引用捕获

    捕获异常时 标准指导是按值抛出 按引用捕获 据我了解 这有两个原因 如果由于内存不足异常而引发异常 我们将不会调用可能终止程序的复制构造函数 如果异常是继承层次结构的一部分 我们可能会对异常进行对象切片 如果我们有一个场景 我们没有在 ca
  • 使用 Microsoft Graph 创建用户

    如何使用 Microsoft graph 创建用户 因为我在保存过程中遇到了权限失败的问题 我确实有几个问题 在图中调用创建用户 API 将在哪里创建用户 是在 Azure AD 还是其他地方 我尝试通过传递 json 和必需的标头来调用创
  • C++ 析构函数:何时释放内存?

    如果我删除一个导致其析构函数被调用的对象 那么内存是在析构函数完成函数中的任何操作之前还是之后被释放 仅当最小派生类子对象被销毁后才会释放内存 所以如果你有 class Base class Derived public Base publ
  • ASP MVC 5 - 403 customError 不起作用

    我正在尝试为我的应用程序创建自定义错误页面 它在大部分情况下都有效 但不适用于403 errors 我的网络配置
  • 在非指针变量和类成员上放置 new

    考虑以下示例 include
  • 从存储过程返回 int 值并在 ASP.NET 代码中检查它以验证登录表单

    当我多次尝试但没有得到有效结果时 使此代码运行的真实顺序是什么 SQL存储过程的代码 set ANSI NULLS ON set QUOTED IDENTIFIER ON GO ALTER PROC dbo login proc usern
  • C# - 命名空间内的类型声明

    在命名空间内而不是在类中声明类型的可能用途是什么 For ex namespace Test public delegate void Ispossible 这是有效的并且不会产生任何编译错误 但我无法想象为什么我们会以这种方式声明它而不是
  • C 中的静态和动态绑定(严格来说是 C,而不是 C++)是什么?

    我最初对发布这个问题感到担忧 以免它重复 但即使在谷歌搜索了许多关键字之后 我在 StackOverflow 上找不到任何解释 C 的静态和动态绑定的链接 尽管有 C 的问题和答案 但是都涉及classes以及显然不适合 C 的东西 Sta
  • XmlDocument Save 使文件保持打开状态

    我有一个简单的 C 函数 可以创建一个基本的 XML 文件并保存 private void CreateXMlFile string Filename string Name string Company XmlDocument doc n
  • 如何获取通过网络驱动器访问的文件的 UNC 路径?

    我正在 VC 中开发一个应用程序 其中网络驱动器用于访问文件 驱动器由用户手动分配 然后在应用程序中选择驱动器 这会导致驱动器并不总是映射到相同的服务器 我该如何获取此类文件的 UNC 路径 这主要是为了识别目的 这是我用来将普通路径转换为

随机推荐