我的意图是使用通用接口来迭代来自各种I / O源的文件。例如,我可能想要一个迭代器,该迭代器在授权允许的情况下会延迟打开文件系统上的每个文件并返回打开的文件句柄。然后,我想使用相同的接口来遍历AWS S3存储桶中的对象。在后一种情况下,迭代器会将每个对象/文件从S3下载到本地文件系统,然后打开该文件,然后再次返回文件句柄。显然,两个迭代器接口的实现方式都将非常不同。
我相信三个最重要的设计目标是这些:
iter++
调用,将返回代表所请求文件句柄的std :: future或PPL pplx :: task。我需要具有与PPL choice(when_any)
等效的功能,因为我希望同时运行多个迭代器。我假定将STL input_iterator作为接口的出发点。毕竟,我看到了这个choice(when_any)
。它不涉及IO,但我看到另一个2014 SO post with a simple example。到目前为止一切顺利。
我开始担心的是,当我阅读诸如“ article from 2001 that allegedly does incorporate IO into a custom STL iterator”之类的文章时。阿克!那篇文章给我的印象是,我无法实现伪装成迭代器的生成器函数的创建意图,可能要等到C ++ 20才能实现。同样,这另一个Generator functions in C++听起来像是在C ++中创建生成器函数的黄蜂巢。
虽然我的自定义迭代器的实现会很复杂,但也许最后两个链接要解决的问题超出了我想要实现的目标。换句话说,也许我的计划没有缺陷?我想知道如果我假设在自定义的input_iterator之后进行惰性生成器实现,那么我会遇到哪些障碍。如果我应该使用其他功能,例如Boost iterator_facade,我希望对“为什么”有一些解释。另外,我想知道我在做什么,是否已经在其他地方实现。也许我才刚刚开始学习的PPL已经为此提供了解决方案?
ps.s。我举了一个S3迭代器的示例,该迭代器懒惰地下载每个请求的文件,然后返回一个打开的文件句柄。是的,我知道这意味着迭代器正在产生副作用,通常我希望避免这种副作用。但是,出于我的预期目的,我不确定采用哪种更干净的方法。
您看过CoroutineTS吗?它随C ++ 20一起提供,并且可以满足您的需求。
某些编译器(GNU 10,MSVC)已经有了一些支持。
您可能感兴趣的标准协程上的特定库功能:
generator<T>
[生成器代表一种协程类型,该协程类型产生一系列类型为T的值,其中值是延迟和同步产生的。
协程小体可以使用co_yield关键字产生T型值。但是请注意,协程主体无法使用co_await关键字;值必须同步产生。
generator<T>
[async_generator代表一个协程类型,该协程类型产生一系列类型为T的值,其中值是延迟产生的,值可以异步产生。
协程体能够同时使用co_await和co_yield表达式。
生成器的消费者可以使用基于co_await基于范围的for循环来消耗这些值。
示例
cppcoro::generator<const std::uint64_t> fibonacci()
{
std::uint64_t a = 0, b = 1;
while (true)
{
co_yield b;
auto tmp = a;
a = b;
b += tmp;
}
}
void usage()
{
for (auto i : fibonacci())
{
if (i > 1'000'000) break;
std::cout << i << std::endl;
}
}
旁注:Boost Asio对多个版本的CoroutineTS提供了实验性支持,因此,如果您愿意,可以将其组合。