C++のCoroutineちょっと使ってみた

C++20でCoroutineが追加されますね。Coroutineについては[こちら](https://www.slideshare.net/yohhoy/20c20)を参照してください。私は東方が好きで[東方弾幕風](https://danmakufu.wiki.fc2.com/)というやつを一時期やってまして、そこにも[同様の機能](https://thelandofcodesandapertures.github.io/Danmakufu-ph3-Official-Documentation/th_dnh_help_v3.html)がありました。それを、今時分が制作しているゲームにも組み込めないかなと。

### 想像と違った。
さっきのサイトの通り、C++で実装されるものは、弾幕風のマイクロスレッドのような便利なものではなく、**それを実装するためのもの**でした。つまり、自分でマイクロスレッドを作るみたいな感じです。そして、弾幕風はメインスレッドに戻るのに対し、こちらは呼び出し元に戻るという違いがあります。

### 壁にあたった
それにしてもこのCoroutine。新しいものということもあってか、日本語の文献が全然ない。自分が知ってる限りで日本語でサンプルとかあるのは2箇所だけ。[^ここ]
でもわかりやすくて助かりました。

#できたもの
![testyieldbig.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286973/163d6f34-8fbb-5ea1-b44c-5a3312f7cc29.gif)
こんな感じに1文字ずつ描画されます(フレームレートとかの関係でそう見えないだけ)。DXライブラリです。

## コード
ジェネレータは先述のサイトとほぼ一緒です。ただ、今回は返り値は必要ないのでとりあえず捨ててます。どうにかしたいな。
とりあえず動くようにしたので余計なこととかもありますのでそこは適宜。

```cpp:task.h
#include <experimental/coroutine>
#define YIELD (co_yield NULL) /*とりあえずNULL返してる。どうにかしたい*/

struct task {
	bool flag = true;
	struct promise_type {
		auto get_return_object() { return task{ handle_type::from_promise(*this) }; }
		std::experimental::suspend_never initial_suspend()noexcept { return {}; }
		std::experimental::suspend_always final_suspend()noexcept { return {}; }
		std::experimental::suspend_always yield_value(void*)noexcept { return {}; }
		void return_void() {}
		void unhandled_exception() { std::terminate(); }
	};
	using handle_type = std::experimental::coroutine_handle<promise_type>;
	explicit task(handle_type h)
		: coro_(h) {}
	task(const task&) = delete;
	task(task&& rhs)
		: coro_(rhs.coro_) { rhs.coro_ = nullptr; }
	~task() {
		if (coro_)
			coro_.destroy();
	}
	void processing() {
		coro_.promise();
	}

	void update() {
		if (!flag) return;
		coro_.resume();
		flag = !coro_.done();
		processing();
	}

	handle_type coro_;
};
```
変更点としては、`bool flag`を追加したくらいです。これにより、終了した場合にタスクの呼び出しをしなくなります。ただ、今回の場合は必要ないです。ホントは`private`にするとかしたほうがいいと思う。


```cpp:print.cpp
/*省略*/
task print(std::string str) {
	std::string b;
	while (1) {
		if (b != str) {
			for (auto c : str) {
				b.push_back(c);
				DrawString(0, 0, b.c_str(), 0x000000);
				YIELD;
			}
		}
		else {
			DrawString(0, 0, b.c_str(), 0x000000);
			YIELD;
		}
	}
	co_return;
}
```

```cpp:main.cpp
/*インクルードとか省略*/
int WINAPI WinMain(/*引数いっぱい*/) {

/*省略*/

	auto DrawString = print("TestString", font);
	while(/*メインループの処理とか*/){
		DrawString.update();
	}

/*省略*/

}
```

使い方としては、戻り値`task`の関数を使用して、中断するところで`YIELD`を書く。基本無限ループの中に突っ込めばいいと思う。一応終わりには`co_return`を書いとくほうがいいと思います。これで、1フレームごとに1文字描画するようになりました。

# 最後に
みんなもっと`coroutine`使って。まだ実装されてなかったりするものもあるけど。MSVCはまだ実験だけど使えるから！動いたから！
そしてもっと日本語の増やして！正直わからんことだらけです。

###ライセンス
ライセンスはCC0です。自由に使用、改変して結構です。
[![CC0](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg "CC0")](http://creativecommons.org/publicdomain/zero/1.0/deed.ja)

#参考
[C++コルーチン拡張メモ](https://qiita.com/yohhoy/items/aeb3c01d02d0f640c067#%E9%9D%9E%E5%90%8C%E6%9C%9F%E5%87%A6%E7%90%86)

[C++ でコルーチン (async/await 準備編)](https://qiita.com/tan-y/items/ae54153ec3eb42f80638#%E3%82%B3%E3%83%AB%E3%83%BC%E3%83%81%E3%83%B3%E3%82%92%E4%BD%BF%E3%81%86)

[20分くらいでわかった気分になれるC++20コルーチン](https://www.slideshare.net/yohhoy/20c20)



[^ここ]: 「参考」の上2つ。