我有一个可调用迭代器,即重复调用直到返回
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++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
类的用法不是标准的。