如何根据输入迭代器创建可视范围

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

代码神箭

template <typename T>
struct lattice_iterator {
   public:
    using difference_type = std::ptrdiff_t;
    using value_type = std::vector<T>;
    using iterator_category = std::input_iterator_tag;

   private:
    struct wrapped_iter {
        T value_;
        std::move_only_function<T(void)> adder_;

        wrapped_iter(const wrapped_iter&) = delete;
        wrapped_iter(wrapped_iter&&) = default;

        wrapped_iter(std::ranges::input_range auto&& range) {
            auto iter = range.begin();
            value_ = *iter;
            adder_ = [iter_ = std::move(iter)]() mutable { return *++iter_; };
        }

        bool operator<(wrapped_iter const& rhs) const {
            return value_ < rhs.value_;
        }

        wrapped_iter& operator++() {
            value_ = adder_();
            return *this;
        }

        T& operator*() { return value_; }
    };

   public:
    std::vector<wrapped_iter> iters_{};
    value_type values_{};

    template <std::ranges::input_range... R>
        requires(std::convertible_to<std::ranges::range_value_t<R>, T> && ...)
    lattice_iterator(R&&... ranges) {
        (iters_.emplace_back(std::forward<R>(ranges)), ...);
        values_ =
            iters_ |
            std::views::transform([](auto&& iter) { return iter.value_; }) |
            std::ranges::to<std::vector>();
    }

    lattice_iterator(lattice_iterator const&) = delete;
    lattice_iterator(lattice_iterator&&) = default;
    lattice_iterator() = delete;

    lattice_iterator& operator=(lattice_iterator&& rhs) = default;

    value_type operator*() const { return values_; }

    lattice_iterator& operator++() {
        std::size_t min_idx = std::ranges::min(
            std::views::iota(0) | std::views::take(iters_.size()), {},
            [this](std::size_t idx) { return values_[idx]; });

        values_[min_idx] = *++iters_[min_idx];
        return *this;
    }

    void operator++(int) { ++*this; }
};

std::generator<int> get_triangles() {
    for (int n = 1;; ++n) {
        co_yield n*(n + 1) / 2;
    }
}

std::generator<int> get_pentagonal() {
    for (int n = 1;; ++n) {
        co_yield n * (3 * n - 1) / 2;
    }
}

std::generator<int> get_hexagonal() {
    for (int n = 1;; ++n) {
        co_yield n * (2 * n - 1);
    }
}

int main() {
    auto lattice = std::ranges::subrange(
        lattice_iterator<int>{get_triangles(), get_pentagonal(),
                              get_hexagonal()},
        std::unreachable_sentinel);

    static_assert(std::same_as<std::vector<int>,
                               std::ranges::range_value_t<decltype(lattice)>>);

    auto nums =
        std::views::filter(
            lattice,
            [](auto&& pack) -> bool {
                static_assert(std::same_as<std::vector<int>, decltype(pack)>);
                auto p0 = pack.front();
                return std::ranges::all_of(pack,
                                           [&p0](auto px) { return px == p0; });
            }) |
        std::views::transform([](auto&& pack) { return pack.front(); }) |
        std::views::take(3) | std::ranges::to<std::vector>();

    std::cout << nums[1] << ' ' << nums[2] << '\n';
}

背景:

  • lattice_iterator
    是一个类似 zip 的包装器,通过递增所有当前输入中最小的字段来进行迭代

  • main中的代码是为了解决this。与我的问题并不真正相关,请原谅我,这个问题不必要地复杂。它是为了学习新的 C++ 功能

我被困在哪里以及我是如何到达这里的

  • 编译器抱怨创建的子范围不是

    viewable range

  • 搜索结果表明唯一不可见的范围实际上是不支持复制构造函数的范围,来自这篇文章

所以基本上,唯一不是可视范围的是左值不可复制视图,因为希望避免引用视图。

  • 输入迭代器,或者本质上是生成器迭代器,根据定义仅保证移动可移动,但不可复制

  • 但是,根据我的经验,生成器作为可视范围,或者至少与 std::views::filter 兼容。

我怀疑我在某个地方做出了错误的推理,导致我将子范围设计为不可见,而它应该是可见的。如果有人能为我指出,我将不胜感激

c++ range
1个回答
0
投票

左值不可复制视图不是可查看范围,但右值视图是。

一个简单的解决方法是将

std::move(lattice)
放入过滤器中。 见神箭

注:我还必须调整 lambda

 中的 
static_assert

© www.soinside.com 2019 - 2024. All rights reserved.