1 #include <iostream>
2 #include <exception>
3 #include <cassert>
4 
5 #if __has_include("coroutine")
6 #include <coroutine>
7 namespace stdcoro = std;
8 #else
9 #include <experimental/coroutine>
10 namespace stdcoro = std::experimental;
11 #endif
12 
13 struct footable : stdcoro::suspend_always {
14 	footable() noexcept = default;
~footablefootable15 	~footable() { assert(released); }
16 	footable(const footable&) = delete;
17 
18 	using coro_handle = stdcoro::coroutine_handle<>;
19 
await_suspendfootable20 	void await_suspend(coro_handle awaiter) noexcept {
21 		std::cout << "suspending to footable " << this << std::endl;
22 		assert(!handle);
23 		handle = awaiter;
24 	}
await_resumefootable25 	void await_resume() noexcept {
26 		std::cout << "resuming from footable " << this << std::endl;
27 		assert(handle);
28 		handle = {};
29 	}
30 
operatorfootable31 	void operator()() noexcept {
32 		std::cout << "operator() on " << this << std::endl;
33 		assert(handle);
34 		handle.resume();
35 		handle = {};
36 	}
37 
releasefootable38 	void release() noexcept { released = true; }
39 private:
40 	coro_handle handle;
41 	bool released = false;
42 };
43 
44 struct footask {
45 	struct promise_type {
46 		using coro_handle = stdcoro::coroutine_handle<promise_type>;
47 
initial_suspendfootask::promise_type48 		stdcoro::suspend_never initial_suspend() noexcept { return {}; }
final_suspendfootask::promise_type49 		stdcoro::suspend_never final_suspend() noexcept { std::cout << "final suspend" << std::endl; return {}; }
unhandled_exceptionfootask::promise_type50 		void unhandled_exception() {}
return_voidfootask::promise_type51 		void return_void() noexcept { std::cout << "coro returns" << std::endl; }
52 
get_return_objectfootask::promise_type53 		footask get_return_object() { return footask{ coro_handle::from_promise(*this) }; }
54 	};
55 
footaskfootask56 	footask(promise_type::coro_handle handle) : handle(handle) {}
~footaskfootask57 	~footask() { assert(handle.done()); }
58 
59 	promise_type::coro_handle handle;
60 };
61 
62 struct bar {
63 	bar() = default;
64 	bar(const bar&) = delete;
65 
66 	footable foo{};
67 	footask task = taskfun();
68 
taskfunbar69 	footask taskfun() noexcept {
70 		std::cout << "coro begin" << std::endl;
71 		co_await foo;
72 		std::cout << "coro end" << std::endl;
73 	}
74 };
75 
main()76 int main() {
77 	bar foobar;
78 	foobar.foo();
79 	assert(foobar.task.handle.done());
80 	std::cout << "releasing" << std::endl;
81 	foobar.foo.release();
82 	std::cout << "done" << std::endl;
83 	return 0;
84 }
85