[コルーチン]operator co_await と await_transform

# はじめに
コルーチンの中断のカスタマイズポイントとして

- `operator co_await`
- `await_transform`

の二つがあります。
コルーチンライブラリを作る際には都合のいいほうを選んで使えばよいと思いますが、これら2つを改めて比べてみました。

ただの雑談：
MSVCがバグってて再開時に値を返すようなAwaiterをawait_transformで実装したら何故か致命的なコンパイルエラーでコンパイルできないケースがあったが試しにoperator co_awaitで実装しなおしたらコンパイルが通ったこともあった
コンパイラのバグは引きたくないですね

# operator co_await

任意の型をAwaiterへ変換する

## 基本形

```cpp
auto operator co_await(const Type&)
{
    return awaiter{};
} 
```

メンバ関数でもOK

```cpp
struct Type
{
     auto operator co_await() const
     {
         return awaiter{};
     } 
};
```


# await_transform

Promise側から指定する形で任意の型をAwaiterに変換する

## 基本形

```cpp
struct promise_type
{
    // 他のメソッド省略…

    auto await_transform(const Type&) const
    {
        return awaiter{};
    }
};
```
なお、
`operator co_await`と`await_transform`両方ある場合は、
**`await_transform`が優先される**

# どちらを使うのが良さそうか

- AwaiterがPromiseに全く依存しない場合
→ **operator co_await**
(await_transformで同じ実装を何度もする必要がなくなるので)

- Promiseごとに変換するAwaiterが型レベルで異なる
  → **await_transform**
  (operator co_awaitの定義をPromiseごとに複数定義はできないので当然)
- それ以外
  → 都合のいいほうを使う

個人的には、Promiseに依存するようなAwaiterは、
なんの問題もなければ**await_transform**を使っておくのがベターそうに思う

# 実装の切り替え

## operator co_await から await_transform
Awaiterが依存するPromiseごとにawait_transformを実装するだけ

(この時await_suspendの仮引数が`std::coroutine_handle<>`で済むようなケースはそもそもPromiseに依存していないのでawait_transformを使うべきではなさそう)

```cpp
auto operator co_await(const Type&)
{
    // something
    
    struct awaiter {
        bool await_ready() const noexcept { return true;}
        
        void await_suspend(std::coroutine_handle<promise_type>)
        {
            // something with promise         
        }
        void await_suspend(std::coroutine_handle<promise_type2>)
        {
            // something with promise2         
        }

        void await_resume() {}        
    };
    return awaiter{}; 
}
```

変換後

```cpp
struct awaiter
{
    bool await_ready() const noexcept { return true;}
    
    void await_suspend(std::coroutine_handle<promise> h)
    {
        // something with promise         
    }
    void await_suspend(std::coroutine_handle<promise2> h)
    {
        // something with promise2         
    }

    void await_resume() {}        
};
struct promise_type
{
    // 他のメソッド省略…

    auto await_transform(const Type&) const
    {
        // something
        return awaiter{};
    }
};
struct promise_type2
{
    // 他のメソッド省略…

    auto await_transform(const Type&) const
    {
        // something
        return awaiter{};
    }
};
```
## await_transform から operator co_await

こちらは処理次第ではそのまま移植できないこともあるので注意がいる

たとえば、await_transformの動作やAwaiterの状態が、Promiseに依存してしまう以下のようなケース

```cpp
struct promise_type
{
    auto await_transform(const Type& v)
    {
        // Promiseの状態に依存して、動作が変わる
        bool ready = this->something(v);
            
        struct awaiter {
            bool ready{};
            
		    bool await_ready() const noexcept
		    {
		    	return ready;
		    }

		    void await_suspend(std::coroutine_handle<>) {}
		    void await_resume() {}        
        };
        // Awaiterの状態がPromiseに依存
        return awaiter{ready}; 
    }
};
```

operator co_awaitでは任意のPromiseの状態にアクセスできないので、同じように実装しようにも上手くいかない。

この場合はもろもろの動作タイミングを`await_suspend`時に遅延されるなどの工夫がいる

```cpp
auto operator co_await(const Type& v)
{
    struct awaiter {
        Type v; // もしPromiseの状態と複合して絡むならフィールドにもつしかない

	    bool await_ready() const noexcept
	    {
            // await_suspendに流れるように中断させる(false)
	    	return false;
	    }

	    bool await_suspend(std::coroutine_handle<promise_type> h)
        {
            // もろもろの動作をawait_suspendに遅延させる
            bool ready = h.promise().something(v);
            return not ready;
        }
	    void await_resume() {}
    };
    return awaiter{v}; 
}
```

`await_suspend`はboolの返り値をもつこともできる
この際に、trueを返せば中断、falseを返せばこのコルーチンを再開させることになります。

上記の例のようにPromiseに依存してawait_readyの結果が変わるような場合は代わりにawait_suspend時点で判断する必要があります。
この時に、**await_readyで返す値と反転することに注意がいります**。
(await_readyはfalseを返すと中断)

```cpp
    return not ready;
```

# まとめ

- コルーチン中断のカスタマイズポイントは2つある
  - `operator co_await`
     - Promiseに依存することなく任意の型をAwaiterに変換 
     - Promiseに依存しないケースならこちらを使うのが良さそう
  - `await_transform`
     - Promiseごとに指定する形で任意の型をAwaiterに変換   
     - Promiseに依存するケースならこちらを使うのが良さそう
- どちらも実装されている場合は`await_transform`が優先
- 相互変換は基本可能そうだが
  - operator co_awaitからawait_transformは、そのまま移植可能
  - await_transformからoperator co_awaitは、そのまま移植できないケースがありうるので工夫が必要