最終更新日時: 2026年06月21日 17時13分27秒 (JST)
Raclamusi が更新

履歴 編集

customization point object
<execution>

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

    namespace std::execution {
      struct bulk_chunked_t { unspecified };
      inline constexpr bulk_chunked_t bulk_chunked{};
    }

## 概要

`bulk_chunked`は、インデクス空間を区間分割したチャンク単位でタスクを一括実行するSenderアダプタである。

`bulk_chunked`はパイプ可能Senderアダプタオブジェクトであり、パイプライン記法をサポートする。

実行制御ライブラリのデフォルト動作では、下記のように振る舞う。

- 並列Scheduler上では、インデクス空間を区間分割されたチャンク単位で並列実行される。
- 明示的にカスタマイズされていなければ、各インデクスに対する処理は逐次実行される。

## 効果

説明用の式`sndr`, `policy`, `shape`, `f`に対して、型`Policy`を`remove_cvref_t<decltype(policy)>`、型`Shape`を`decltype(auto(shape))`、型`Func`を`decay_t<decltype((f))>`とする。下記いずれかの条件をみたすとき、呼び出し式`bulk_chunked(sndr, policy, shape, f)`は不適格となる。

- `decltype((sndr))`が`sender`を満たさない、もしくは
- `is_execution_policy_v<Policy> == false`、もしくは
- `Shape`が`integral`を満たさない、もしくは
- `Func`が`copy_constructible`のモデルでないとき。

そうでなければ、呼び出し式`bulk_chunked(sndr, policy, shape, f)`は下記と等価。

    make-sender(bulk_chunked, product-type<see below, Shape, Func>{policy, shape, f}, sndr)

`product-type`の第1テンプレート引数は、`Policy`が`copy_constructible`のモデルであるとき`Policy`となる。そうでなければ、`const Policy&`となる。

### Senderアルゴリズムタグ `bulk_chunked`

Senderアルゴリズム動作説明用のクラステンプレート`impls-for`に対して、下記の特殊化が定義される。

    namespace std::execution {
      template<>
      struct impls-for<bulk_chunked_t> : default-impls {
        static constexpr auto complete = see below;

        template<class Sndr, class... Env>
        static consteval void check-types();
      };
    }

`impls-for<bulk_chunked_t>::complete`メンバは、下記ラムダ式と等価な関数呼び出し可能なオブジェクトで初期化される。

    []<class Index, class State, class Rcvr, class Tag, class... Args>
      (Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept
      -> void requires see below {
        if constexpr (same_as<Tag, set_value_t>) {
          auto& [policy, shape, f] = state;
          constexpr bool nothrow = noexcept(f(auto(shape), auto(shape), args...));
          TRY-EVAL(rcvr, [&]() noexcept(nothrow) {
            f(static_cast<decltype(auto(shape))>(0), auto(shape), args...);
            Tag()(std::move(rcvr), std::forward<Args>(args)...);
          }());
        } else {
          Tag()(std::move(rcvr), std::forward<Args>(args)...);
        }
      }

型`Tag`が`set_value_t`以外の型であるとき、もしくは式`f(auto(shape), auto(shape), args...)`が適格なときに限って、上記ラムダ式のrequires節が満たされる。

メンバ関数`impls-for<bulk_chunked_t>::check-types`の効果は下記の通り。

    auto cs = get_completion_signatures<child-type<Sndr>, FWD-ENV-T(Env)...>();
    auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {
      if constexpr (!invocable<remove_cvref_t<data-type<Sndr>>, Ts&...>)
        throw unspecified-exception();
    };
    cs.for-each(overload-set{fn, [](auto){}});

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

Receiver接続時に、関連付けられた実行ドメインに対して`execution::transform_sender`経由でSender変換が行われる。 デフォルト実行ドメインでは無変換。

説明用の式`out_sndr`を`bulk_chunked(sndr, policy, shape, f)`の戻り値 Senderとし、式`rcvr`を式`connect(out_sndr, rcvr)`が適格となるReceiverとする。式`connect(out_sndr, rcvr)`は開始(start)時に下記を満たす非同期操作を生成しない場合、動作は未定義となる。

- 説明用の`args`を`sndr`の値完了結果を参照する左辺値式のパック、または`copy_constructible`のモデルであるならばそれらの値のdecayコピーのパックとする。`sndr`が値完了したとき、
  - `out_sndr`もまた値完了するとき、範囲`[0, shape]`にある型`Shape`の0個以上の`b`と`e`のペアに対して`f(b, e, args...)`を呼び出す。このとき`b < e`であり、かつ`0`から`shape`までの型`Shape`の全ての`i`において、`b`と`e`のペアに対して`i`が範囲`[b, e)`にあるような呼び出しが正確に1回だけ存在する。
  - `out_sndr`が`set_error(rcvr, eptr)`で完了するとき、エラー完了ハンドラが呼び出される前に非同期操作は`f`呼び出しのサブセットを呼び出す可能性があり、`eptr`は下記いずれかを指す`exception_ptr`となる。
    - `f`呼び出しから送出された例外、または
    - 処理系が要求リソースの確保に失敗したときは`bad_alloc` 例外、または
    - `runtime_error`から派生された例外。
  - `out_sndr`が`set_stopped(rcvr)`で完了するとき、停止完了ハンドラが呼び出される前に非同期操作は`f`呼び出しのサブセットを呼び出す可能性がある。
- `sndr`が`set_value`で完了しないとき、その完了操作は`recv`に転送される。
- パラメータ`policy`は、アルゴリズムに対応した非同期操作の実行を並列化する方法、および`f`に適用する方法を規程する。並列アルゴリズム要素アクセス関数に対する権限と要件は`f`に適用される。

## 例

    #include <print>
    #include <execution>
    namespace ex = std::execution;

    int main()
    {
      ex::sender auto sndr =
        ex::just()
        | ex::bulk_chunked(3, ex::seq,
            [](int begin, int end) {
              for (int i = begin; i < end; i++) {
                std::println("{}", i);
              }
            });
      std::this_thread::sync_wait(sndr);
    }

### 出力

    0
    1
    2

## バージョン

### 言語

- C++26

### 処理系

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

## 関連項目

- `execution::bulk`
- `execution::bulk_unchunked`
- `execution::parallel_scheduler`

## 参照

- P2300R10 `std::execution`
- P2079R10 Parallel scheduler
- P3481R5 `std::execution::bulk()` issues
- P3557R3 High-Quality Sender Diagnostics with Constexpr Exceptions
- P3826R5 Fix Sender Algorithm Customization