1: like most of C++ one would way
So on WinRT it is hardly any different from what C++/CX allowed for in concepts.
Basically how the library realizes this is opaque to the user and indeed it does things like reuse low level primitives available in each of the platforms. Basically, at it's lowest level it is simply syntactic sugar for callback based implementations common in platforms that have things like Futures, Promises, etc.
In fact it's easy to integrate any third party library that provides similar constructs and pretend that they are suspend functions. E.g. the suspendCancellableCoRoutine builder can take anything that has a success and fail callback and turn it into suspending code blocks. For example Spring supports coroutines and flows out of the box now and provides deep integration with its own reactive webflux framework. So, you can write a controller that is a suspend function that returns a flow and it just works as a nice reactive endpoint.
I actually would expect that these new C++ capabilities will also find their way into Kotlin's native coroutine implementation eventually. Kotlin native is still in Beta but seems popular for cross platform IOS and Android library development currently.
Kotlin's coroutine library took quite a while to get right for the Kotlin developers and evolved a lot between Kotlin 1.2 and 1.4. Parts of it are still labelled as experimental. Particularly, reactive flows are a relatively late addition and have already had a big impact on e.g. Android and server-side programming.
I believe that the design is both unneededly complex and too unflexible, but this is the only design that managed to get enough traction to get into the standard and it took forever. There are competing designs and improvements, we will have to see if they will make it into the standard.
I also would like if std::variant were a language feature, not library :)
I just sat down with the tutorial and banged out what I consider to be a holy grail for quality of life. Alas, it's about 50 lines of ugly boilerplate. I'm omitting it, in part because it's untested, but mostly because I'm embarrassed to share that much C++ in a public forum. If anybody close to the C++ standards is listening... please make this boilerplate not suck so hard.
template<typename T>
struct CoroutineIterator {
left for the reader!
hint: start with the ReturnObject5 struct in the article,
and add standard iterator boilerplate
}
//! yields the integers 0 through `stop`, except for `skip`
CoroutineIterator<int> skip_iter(int skip, int stop) {
for(int i=0;i<stop;i++)
if(i != skip)
co_yield i;
}
int main() {
for(auto &i : skip_iter(15, 20)) {
std::cout << i << std::endl;
}
} skip_iter(int skip, int stop)
for(int i=0;i<stop;i++)
Wouldn't work with complex types, boxed integers and so on? Because calling postfix ++ would be a function/method call? class Stooge {...};
CoroutineIterator<Stooge> three_stooges() {
co_yield Stooge("Larry");
co_yield Stooge("Curly");
co_yield Stooge("Moe");
}C++ coroutines do support allocators [1], so it is not a huge issue, but it does complicate the design further.
[1] the compiler is also allowed to elide the allocation, but a) it is not clear how this is different from the normal allocation elision allowance that compilers already had, and b) it is a fragile optimization.
There are already proposals to improve on the design, but we will have to see if they work out.
But for folks working on gamedev libs, high-performance async, etc would probably prefer making their own task/promise-type for hand-crafted customization.