Standard C++ generator
The code below demonstrates how standard C++23 synchronous generator works:
#include <boost/cobalt.hpp>
#include <iostream>
#include <generator>
namespace cobalt = boost::cobalt;
std::generator<int> numbers()
{
for (int i = 1; i <= 5; ++i)
{
co_yield i;
}
}
cobalt::main co_main(int argc, char* argv[])
{
for (int v : numbers())
{
std::cout << "Got value: " << v << std::endl;
}
co_return 0;
}
Cobalt generator
I replaced standard generator with cobalt generator:
cobalt::generator<int> numbers2()
{
for (int i = 1; i <= 5; ++i)
{
co_yield i;
}
}
and got the following warning:
warning C4033: 'numbers2' must return a value
so it wonts me to add a fake co_return
and I also use the generator is a different way, because it is asynchronous:
cobalt::generator<int> numbers2()
{
for (int i = 1; i <= 5; ++i)
{
co_yield i;
}
co_return 0;
}
cobalt::main co_main(int argc, char* argv[])
{
auto gen = numbers2(); // создаём генератор
while (auto val = co_await gen)
{
std::cout << "Got value: " << val << std::endl;
}
co_return 0;
}
This code works and prints the following:
Got value: 1
Got value: 2
Got value: 3
Got value: 4
Got value: 5
Using BOOST_COBALT_FOR macro
Replaced co_main
with the following:
cobalt::main co_main(int argc, char* argv[])
{
auto gen = numbers2(); // создаём генератор
BOOST_COBALT_FOR(auto val, gen)
{
std::cout << "Got value: " << val << std::endl;
}
co_return 0;
}
and got the following output:
Got value: 1
Got value: 2
Got value: 3
Got value: 4
Got value: 5
Got value: 0
True asynchronous generator
cobalt::generator<int> numbers3(asio::any_io_executor exec)
{
asio::steady_timer timer(exec);
for (int i = 1; i <= 5; ++i)
{
timer.expires_after(500ms);
co_await timer.async_wait(cobalt::use_op);
co_yield i;
}
co_return 0;
}
cobalt::main co_main(int argc, char* argv[])
{
auto exec = co_await cobalt::this_coro::executor;
auto gen = numbers3(exec);
BOOST_COBALT_FOR(auto val, gen)
{
std::cout << "Got value: " << val << std::endl;
}
co_return 0;
}
Multiple iterating coroutines
Tried to iterate on two spawned coroutines:
cobalt::generator<int> number_source(int count)
{
auto exec = co_await cobalt::this_coro::executor;
asio::steady_timer timer(exec);
for (int i = 1; i <= count; ++i)
{
timer.expires_after(500ms);
co_await timer.async_wait(cobalt::use_op);
co_yield i;
}
co_return 0;
}
using GenPtr = std::shared_ptr<cobalt::generator<int>>;
cobalt::task<void> consumer(int id, GenPtr gen)
{
auto exec = co_await cobalt::this_coro::executor;
asio::steady_timer timer(exec);
while (true)
{
auto val = co_await *gen;
if (!val)
break; // the channel is closed
std::cout << "Consumer " << id << " got: " << val << "\n";
timer.expires_after(500ms);
co_await timer.async_wait(cobalt::use_op);
}
std::cout << "Consumer " << id << " finished\n";
co_return;
}
cobalt::main co_main(int argc, char* argv[])
{
GenPtr gen = std::make_shared<cobalt::generator<int>>(number_source(10));
auto exec = co_await cobalt::this_coro::executor;
cobalt::spawn(exec, consumer(1, gen), boost::asio::detached);
cobalt::spawn(exec, consumer(2, gen), boost::asio::detached);
co_return 0;
}
but got a result that I did not expect, coroutine #2 did not print anything:
Consumer 1 got: 1
Consumer 1 got: 2
Consumer 1 got: 3
Consumer 1 got: 4
Consumer 1 got: 5
Consumer 1 got: 6
Consumer 1 got: 7
Consumer 1 got: 8
Consumer 1 got: 9
Consumer 1 got: 10
Consumer 1 finished
How to exit from a generator without returning a value
https://github.com/boostorg/cobalt/issues/176