如何实现隐藏可移动输入迭代器?

问题描述 投票:0回答:1

我有一个输入迭代器,可以遍历文件并解析其中的记录。每个解析的记录都存储在迭代器中并归其所有(“隐藏”)。

记录并不轻量,而且数量很多,因此复制这些值是很不幸的。我希望能够将它们移出迭代器,所以我像这样定义取消引用:

Record& operator*() { return this->record; }

此代码有效:

Record r = std::move(*it); // no copy

然后我想使用适当的 C++20 概念来实现此迭代器的编译时安全性,并且我添加了:

static_assert(std::input_iterator<Iterator>);

它失败了,因为

std::input_iterator
的一部分 -
std::indirectly_readable
- 要求
const Iterator
是可解引用的(相关问题:为什么简单的迭代器不可读?)。我无法让我的
operator*
const
上工作,因为那样它必须返回 const 引用,并且
move
实际上会复制:

const Record& operator*() const { return this->record; }

Record r = std::move(*it); // copy, 'cause can't move const objects

我发现使用

static_assert(std::input_or_output_iterator)
可以与可变取消引用一起使用。对于静态检查来说可能没问题,但我发现它很混乱,因为我的迭代器在概念上不是一个output_iterator。

另一个相关问题是

std::move_iterator
不适用于这个可变解引用运算符,因为它的
operator*()
是 const,定义为:

reference operator*() const { return ranges::iter_move(__current_); }

其中

__current_
将绑定到我的 Iterator 实例,并且在此上下文中它将具有类型
const Iterator
,iter_move 想要取消引用并失败,因为它不支持不可变的取消引用(即使它通过添加
 来实现) const
,它无法正常工作,它会欺骗性地复制值而不是移动)。

实现隐藏迭代器的可移动性并使 move_iterator 工作的替代设计是什么?

c++ stl c++20
1个回答
0
投票

迭代器的移动或复制成本较低。您不应该将

Record
保留在迭代器中。许多范围/范围适配器所做的是将其保留在范围内,并简单地将指针保留在迭代器中:

struct record_range {
private:
    Record cache;
public:
    struct iterator {
    private:
        friend record_range;
        record_range* parent;
        explicit iterator(record_range* parent) : parent(parent) {}
    public:
        using difference_type = std::ptrdiff_t;
        using value_type = Record;
        Record& operator*() const { return parent->cache; }
        iterator& operator++() { advance_record(parent->cache); return *this; }
        void operator++(int) { ++*this; }
    };
    friend bool operator==(iterator it, std::default_sentinel_t) {
        return is_past_the_end_record(it.parent->cache);
    }
    iterator begin() { read_first_record(cache); return iterator{ this }; }
    std::default_sentinel_t end() const { return {}; }
};

static_assert(std::input_iterator<record_range::iterator>);
static_assert(std::ranges::input_range<record_range>);
© www.soinside.com 2019 - 2024. All rights reserved.