I took the implementation of coroutines for std::future from the documentation at https://en.cppreference.com/w/cpp/coroutine/coroutine_traits and modified it for std::optional
#include <coroutine>
#include <optional>
#include <iostream>
template <typename T, typename... Args>
requires(!std::is_void_v<T> && !std::is_reference_v<T>)
struct std::coroutine_traits<std::optional<T>, Args...> {
struct promise_type : std::optional<T> {
std::suspend_never initial_suspend() const noexcept { return {}; }
std::suspend_never final_suspend() const noexcept { return {}; }
std::optional<T> get_return_object() noexcept {
return *this;
}
void return_value(const T &value)
noexcept(std::is_nothrow_copy_constructible_v<T>) {
**this = value;
}
void return_value(T &&value)
noexcept(std::is_nothrow_move_constructible_v<T>) {
**this = std::move(value);
}
void unhandled_exception() noexcept {
}
};
};
template <typename T>
auto operator co_await(std::optional<T> optional) noexcept
requires(!std::is_reference_v<T>) {
struct awaiter : std::optional<T> {
bool await_ready() const noexcept {
return static_cast<bool>(*this);
}
void await_suspend(std::coroutine_handle<> cont) const {
cont.destroy();
}
T await_resume() { return **this; }
};
return awaiter{std::move(optional)};
}
void process(std::string msg, std::optional<int> x)
{
if(x)
std::cout << msg << " has value " << * x << std::endl;
else
std::cout << msg << " no value" << std::endl;
}
std::optional<int> comput(std::optional<int> a, std::optional<int> b)
{
int c = (co_await a) * (co_await b);
process("inner", c);
co_return c;
}
std::optional<int> gen(){
co_return 15;
}
int main(){
process("final 0", gen());
process("final 1", comput(10, 11));
process("final 2", comput(std::nullopt, 11));
process("final 3", comput(10, std::nullopt));
process("final 4", comput(10, 33));
}
The results look like
final 0 no value
inner has value 110
final 1 no value
final 2 no value
final 3 no value
inner has value 330
final 4 no value
I would have expected the results to look like
final 15 no value
inner has value 110
final 1 has value 110
final 2 no value
final 3 no value
inner has value 330
final 4 has value 330
It seems to be almost working because the output of the temporary generated by the lines is correct.
int c = (co_await a) * (co_await b);
process("inner", c);
Godbolt link https://godbolt.org/z/Woah8K5rE