当前位置: 首页 > 知识库问答 >
问题:

我的自定义std::ranges迭代器缺少什么?

房冥夜
2023-03-14

我想为客户数据结构提供一个视图,它有自己的迭代器。我编写了一个小程序来测试它,如下所示。如果我取消对begin()的注释,它就会工作。但是如果我使用DummyIter,那么我会得到一个编译错误。

在我的完整程序中,我实现了一个完整的迭代器,但为了简单起见,我把它缩小到了必要的函数。

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

template<class T>
struct DummyIter
{
  using iterator_category = std::random_access_iterator_tag;
  using value_type = T;
  using difference_type = std::ptrdiff_t;

  DummyIter() = default;

  auto operator*() const { T t; return t; }

  auto& operator++() { return *this; }

  auto operator++(int val) { DummyIter tmp = *this; ++*this; return tmp; }

  auto operator==(const DummyIter& iter) const { return true; }
};

template<class V>
struct DummyView : std::ranges::view_interface<DummyView<V>>
{
  //auto begin() const { return std::ranges::begin(v); }
  auto begin() const { return DummyIter<int>(); }

  auto end() const { return std::ranges::end(v); }

  V v;
};

int main() {
  auto view = DummyView<std::vector<int>>();
  view | std::views::filter([](auto i) { return i > 0; });
}

我使用的是GCC 11.1.0。我在迭代器中缺少了什么使其符合范围?

error: no match for 'operator|' (operand types are 'DummyView<std::vector<int> >' and 'std::ranges::views::__adaptor::_Partial<std::ranges::views::_Filter, main()::<lambda(auto:15)> >')
   37 |   view | std::views::filter([](auto i) { return i > 0; });
      |   ~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |   |                        |
      |   |                        std::ranges::views::__adaptor::_Partial<std::ranges::views::_Filter, main()::<lambda(auto:15)> >
      |   DummyView<std::vector<int> >

共有3个答案

宰父正真
2023-03-14

检查此类范围的方法是:

  1. 验证您的迭代器是一个input_iterator
  2. 验证您的哨兵是一个sentinel_for您的迭代器。

这些检查将告诉您缺少哪些功能

在这种情况下,即:

using I = DummyIter<int>;
using S = std::vector<int>::const_iterator;

static_assert(std::input_iterator<I>);   // ok
static_assert(std::sentinel_for<S, I>);  // error

问题是S不是sentinel_for

因此,您需要添加另一个运算符==DummyIter

严斌
2023-03-14

这不起作用,因为开始结束返回类型不匹配。所以基本上这些迭代器不能相互比较。

证明:

  • 这是带有额外静态断言的代码

最低要求是开始()结束()的结果是可比的。当不知道范围的大小时,开始()结束()的不同类型是有用的。这里有一个关于哨兵的很好的解释(在注释中提到)。

黄隐水
2023-03-14

因为您的DummyView不符合range的概念,准确地说,就是视图的返回类型。end()不能用作视图的哨兵。begin(),因为没有合适的运算符==()来与std::vector进行比较

解决方法只是添加bool运算符==(std::向量

template<class T>
struct DummyIter {
  // ...
  bool operator==(std::vector<T>::const_iterator) const;
};

演示

 类似资料:
  • 我可以看到返回。但是现在已经添加到C++20标准中,为什么返回?cppreference指定: 返回值 等于last的迭代器。 这个选择背后的理性是什么? 与相比,用例的优势是什么?

  • 我无法让我的用户定义的容器使用std::ranges。如果迭代器只是一个< code>int*的话,我的容器可以工作,但是一旦我创建了自己的迭代器类,就会出现编译器错误。 这是有效的。 https://godbolt.org/z/nxr1qe 使用我自己的迭代器,它不起作用。 https://godbolt.org/z/o9rzhf 为了实现这一点,是否需要为<code>std::ranges</

  • 我知道这个问题在这个论坛上已经被问过好几次了。但我仍在发帖,因为没有一个答案看起来是具体的。专家们,你们能帮我理解什么时候使用迭代器吗。当我们有一个非常大的数据集时,我们是理想地使用它,还是当我们有大量数据要返回时,将其用作方法的返回类型?

  • 我想在JSF应用程序中配置自定义范围。我们在WebSphere8.0/8.5上使用JSF2.0和Primefaces 5.3.17。目前,我们有RequestScope核心和SessionScope模型bean以及命名注释。模型通过注入传递到核心。现在,我们需要提供一种在许多浏览器选项卡上与模型并行工作的方法。我们的想法是使用过滤器将生成的选项卡id注入到响应中,然后,稍后从post请求中提取它,

  • 我试图编写一些代码来执行函数式序列的创建。我写了一个函数range它返回一个对象,你可以迭代它,foreach样式,以遍历数字a,a 1,...,b - 1。然后我写了另一个函数map它返回另一个可迭代对象,其中序列中的每个元素都是使用可迭代对象的相应元素调用的结果。 如果我使用< code>-O1或更低版本进行编译,这将按预期工作;使用< code>-O2或更高版本,我的foreach循环(在底

  • 考虑一个大型内存容器。在这个简单的例子中 span允许我在内存上创建一个轻量级视图。现在,我只想打印跨度: 输出: 现在我想制作子集(这是实际上作为视图变得有用的地方)。我可以使用迭代器来指定我的范围并从调用这个构造函数(3) 但这行不通: C没有与参数列表匹配的构造函数实例参数类型为:(std::\u Vector\u iterator 有可能使用接受指针和大小的构造函数(2): 但这违背了迭代