最終更新日時: 2026年06月08日 10時13分52秒 (JST)
yoh が更新

履歴 編集

customization point object
<execution>

# std::execution::as_awaitable(C++26)

    namespace std::execution {
      struct as_awaitable_t { unspecified };
      inline constexpr as_awaitable_t as_awaitable{};
    }

## 概要

`as_awaitable`は、オブジェクトを特定のコルーチン内でAwaitableに変換するカスタマイゼーションポイントオブジェクトである。

Promise型`p`をもつコルーチンにおいて、Await式`co_await as_awaitable(expr, p)`は下記のように動作する。

- 式`expr.as_awaitable(p)`が有効ならば、同式が返すAwaitableオブジェクトに対してAwait式を実行する。
- `expr`がSender型かつ`get_await_completion_adaptor`問い合わせに対応する場合、同問い合わせが返すSenderアダプタを`expr`に適用した結果を`adapted-expr`とする。
- `expr`（または上記ステップの`adapted-expr`）が単一の値を送信するSenderであり、Promise型が停止完了ハンドラを定義するならば、下記動作を行う。
  - Senderを接続(connect)し、結果Operation StateをAwaitableオブジェクトに格納する。
  - コルーチンを中断し、Operation Stateを開始(start)する。
  - クエリオブジェクトによるReceiver環境への問い合わせは、Promise型に関連付けられた環境(`get_env`)へと転送される。
  - Senderが値完了した場合、送信値をAwait式の結果としてコルーチンを再開する。
  - Senderがエラー完了した場合、エラー値を例外としてコルーチンから再送出する。
  - Senderが停止完了した場合、停止完了ハンドラ(`unhandled_stopped`)が返す別のコルーチンを再開させる。
- そうでなければ、式`expr`に対してAwait式を実行する。

## 効果

説明用の式`expr`と左辺値`p`に対して、型`Expr`を`decltype((expr))`、型`Promise`を`decay_t<decltype((p))>`とする。

呼び出し式`as_awaitable(expr, p)`は、`expr`と`p`の評価が不定順で順序付けられることを除いて、下記と等価。

- 適格であるならば、式`expr.as_awaitable(p)`
  - 適格要件 : 同式の型を`A`としたとき、`is-awaitable<A, Promise> == true`であるべき。
- そうではなく、下記の式が適格であり`sender_in<Expr, env_of_t<Promise>>`が`true`、かつ`single-sender-value-type<Expr, env_of_t<Promise>>`が適格ならば、`p`が1回だけ評価されることを除いて下記と等価。

      adapt-for-await-completion(transform_sender(expr, get_env(p))).as_awaitable(p)

- そうではなく、`decltype(GET-AWAITER(expr))`が`is-awaiter<Promise>`を満たすならば、式`(void(p), expr)`
- そうではなく、下記の式が適格であり`sender_in<Expr, env_of_t<Promise>>`が`true`、かつ`single-sender-value-type<Expr, env_of_t<Promise>>`が適格ならば、`p`が1回だけ評価されることを除いて下記と等価。

      sender-awaitable{adapt-for-await-completion(transform_sender(expr, get_env(p))), p}

- そうでなければ、式`(void(p), expr)`

## 説明専用エンティティ

### 式`adapt-for-await-completion`

式`adapt-for-await-completion(s)`は下記と等しい。

- 式が適格であるならば、`s`が1回だけ評価されることを除いて、`get_await_completion_adaptor(get_env(s))(s)`
- そうでなければ、`s`

### コンセプト`awaitable-sender`

    namespace std::execution {
      template<class Sndr, class Promise>
      concept awaitable-sender =
        single-sender<Sndr, env_of_t<Promise>> &&
        sender-to<Sndr, typename sender-awaitable<Sndr, Promise>::awaitable-receiver> &&  // see below
        requires (Promise& p) {
          { p.unhandled_stopped() } -> convertible_to<coroutine_handle<>>;
        };
    }

### コンセプト`has-queryable-await-completion-adaptor`

    namespace std::execution {
      template<class Sndr>
      concept has-queryable-await-completion-adaptor =  // exposition only
        sender<Sndr>
        && requires(Sndr&& sender) {
          get_await_completion_adaptor(get_env(sender));
        };
    }

### クラステンプレート`sender-awaitable`

    namespace std::execution {
      template<class Sndr, class Promise>
      class sender-awaitable {
        struct unit {};                                           // exposition only
        using value-type =                                        // exposition only
          single-sender-value-type<Sndr, env_of_t<Promise>>;
        using result-type =                                       // exposition only
          conditional_t<is_void_v<value-type>, unit, value-type>;
        struct awaitable-receiver;                                // exposition only

        variant<monostate, result-type, exception_ptr> result{};  // exposition only
        connect_result_t<Sndr, awaitable-receiver> state;         // exposition only

      public:
        sender-awaitable(Sndr&& sndr, Promise& p);
        static constexpr bool await_ready() noexcept { return false; }
        void await_suspend(coroutine_handle<Promise>) noexcept { start(state); }
        value-type await_resume();
      };
    }

### 式`AS-EXCEPT-PTR`

説明用の式`err`に対して`decltype((err))`を型`Err`としたとき、式`AS-EXCEPT-PTR(err)`を下記の通り定義する。

- `decay_t<Err>`が`exception_ptr`型と等しければ、`err`となる。このとき、事前条件として`!err == false`であること。
- そうではなく、`decay_t<Err>`が`error_code`型と等しければ、`make_exception_ptr(system_error(err))`となる。
- そうでなければ、`make_exception_ptr(err)`となる。

### クラステンプレート`awaitable-receiver`

説明専用のクラステンプレート`sender-awaitable<Sndr, Promise>::awaitable-receiver`は下記の通り定義される。

    struct awaitable-receiver {
      using receiver_concept = receiver_tag;
      variant<monostate, result-type, exception_ptr>* result-ptr;  // exposition only
      coroutine_handle<Promise> continuation;                      // exposition only
      // see below
    };

説明用の式`rcvr`を`awaitable-receiver`型の右辺値、`crcvr`を`rcvr`をconst参照する左辺値、`vs`を式パック、`err`を`Err`型の式とする。ある部分式`expr`に対する`MAKE-NOEXCEPT(expr)`を`[] noexcept -> decltype(auto) { return (expr); }()`と等価な式とする。このとき

- 式`set_value(rcvr, vs...)`は下記と等価。`constructible_from<result-type, decltype((vs))...>`を満たすこと。

      try {
        rcvr.result-ptr->template emplace<1>(vs...);
      } catch(...) {
        rcvr.result-ptr->template emplace<2>(current_exception());
      }
      MAKE-NOEXCEPT(rcvr.continuation.resume());

- 式`set_error(rcvr, err)`は下記と等価。

      try {
        rcvr.result-ptr->template emplace<2>(AS-EXCEPT-PTR(err));
      } catch(...) {
        rcvr.result-ptr->template emplace<2>(current_exception());
      }
      MAKE-NOEXCEPT(rcvr.continuation.resume());

- 式`set_stopped(rcvr)`は下記と等価。

      MAKE-NOEXCEPT(static_cast<coroutine_handle<>>(rcvr.continuation.promise().unhandled_stopped()).resume());

- `forwarding-query`を満たす型の式`tag`とパック式`as`に対して、式`get_env(crcvr).query(tag, as...)`は下記と等価。

      tag(get_env(as_const(MAKE-NOEXCEPT(crcvr.continuation.promise()))), as...)

    sender-awaitable(Sndr&& sndr, Promise& p);

- 効果 : `state`を下記で初期化する。

      connect(std::forward<Sndr>(sndr),
              awaitable-receiver{addressof(result), coroutine_handle<Promise>::from_promise(p)})

    value-type await_resume();

- 効果 : 下記と等価。

      if (result.index() == 2)
        rethrow_exception(get<2>(result));
      if constexpr (!is_void_v<value-type>)
        return std::forward<value-type>(get<1>(result));

## カスタマイゼーションポイント

`expr`に対して、適格であるならば式`expr.as_awaitable(p)`が呼び出される。

`expr`がSender型かつ関連付けられた属性がクエリオブジェクト`get_await_completion_adaptor`に対応するとき、`expr`に対して同クエリオブジェクトが返すSenderアダプタを適用してからAwaitableオブジェクトへ変換する。

## バージョン

### 言語

- C++26

### 処理系

- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??

## 関連項目

- `execution::with_awaitable_senders`
- `execution::get_await_completion_adaptor`
- C++20 コルーチン

## 参照

- P2300R10 `std::execution`
- P3396R1 std::execution wording fixes
- P3570R2 optional variants in sender/receiver
- LWG4358 §[exec.as.awaitable] is using "Preconditions:" when it should probably be described in the constraint
- LWG4360 `awaitable-sender` concept should qualify use of `awaitable-receiver` type
- LWG4133 `awaitable-receiver`'s members are potentially throwing
- LWG4361 `awaitable-receiver::set_value` should use Mandates instead of constraints
- P3941R4 Scheduler Affinity
- P4159R0 Make `sender_in` and `receiver_of` exposition-only