如何在不预先读取下一个元素的情况下为基于范围的 for 循环调整可调用迭代器

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

我有一个可调用迭代器,即重复调用直到返回

std::function<std::optional<T>()>
std::nullopt
实例。将所有返回值收集到
std::vector
中很容易,但我正在寻找某种适配器以在(纯)
for
循环中使用它:

https://godbolt.org/z/M3G3qdP39

#include <functional>
#include <iostream>
#include <optional>
#include <vector>

std::function<std::optional<int>()> callableIterator() {
    return [value = 0]() mutable -> std::optional<int> {
        if (value == 10) {
            return {};
        }
        return value++;
    };
}

template <typename It>
auto collectCallable(It&& it) {
    using T = std::decay_t<decltype(*it())>;
    std::vector<T> result;
    while (auto e = it()) {
        result.push_back(std::move(*e));
    }
    return result;
}

template <typename It>
struct CallableIterable {
    It it;
    using T = std::decay_t<decltype(*it())>;

    CallableIterable(It&& it) : it(std::move(it)) {}

    struct EndIterator {};

    struct Iterator {
        CallableIterable& iterable;
        std::optional<T> valueHolder;

        Iterator(CallableIterable& iterable) : iterable(iterable), valueHolder(iterable.it()) {}

        Iterator& operator++() { 
            valueHolder = iterable.it();
            return *this;
        }

        bool operator!=(EndIterator) { return !!valueHolder;}

        T operator*() { return *valueHolder; }

    };

    Iterator begin() {
        return {*this};
    }

    EndIterator end() {
        return {};
    }
};

int main() {
    for (auto value : collectCallable(callableIterator())) {
        std::cout << value << std::endl;
    }
    for (auto value : CallableIterable(callableIterator())) {
        std::cout << value << std::endl;
    }
    return 0;
}

为了确定迭代器是否已耗尽,我需要读取always read

CallableIterable::Iterator++()
中的一个元素。是否有基于
for
的解决方案不需要这个?

c++
1个回答
0
投票

不确定它是否完全回答了问题,但这是一个依赖协程的解决方案(等等

c++20
):

#include <functional>
#include <iostream>
#include <optional>
#include <__generator.hpp>  // https://github.com/lewissbaker/generator

std::function<std::optional<int>()> callableIterator() {
    return [value = 0]() mutable -> std::optional<int> {
        if (value == 10) {
            return {};
        }
        return value++;
    };
}

template <typename It>
auto generator (It&& it) -> std::generator<std::decay_t<decltype(*it())>>
{
    while (auto e = it())  { co_yield *e; }
}

int main() 
{
    for (auto value : generator(callableIterator())) 
    {
        std::cout << value << std::endl;
    }
    
    return 0;
}

实际上,它模仿您的

collectCallable
,而无需创建一个容器,其唯一用途是在 for-range 循环中迭代。

但是请注意

generator
类的用法不是标准的。

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