yohhoyの日記

技術的メモをしていきたい日記

C++26 Executionライブラリ:Sender完了シグネチャ集合

C++2c(C++26)実行制御ライブラリ(execution control library)(→id:yohhoy:20250609)において、Sender型の完了シグネチャ集合(set of completion signatures)の宣言方法。[P3557R3採択後WD N5014*1準拠]

自作SenderクラスMySenderの完了シグネチャ集合は、コンパイル時評価される静的メンバ関数テンプレートMySender::get_completion_signaturesの戻り値型execution::completion_signatures<Sigs...>によって表現する。実行制御ライブラリからはexecution::get_completion_signaturesを経由したexecution::completion_signatures_of_tエイリアステンプレートによりSender完了シグネチャ集合にアクセスされる。

// C++2c
#include <execution>
namespace exec = std::execution;

// 非依存Senderクラス(詳細後述)
struct MySender {
  using sender_concept = exec::sender_t;

  // MySenderの完了シグネチャ集合を宣言
  // 値完了     set_value_t(int)
  // エラー完了 set_error_t(exception_ptr)
  // 停止完了   set_stopped_t()
  template <class Self>
  static consteval auto get_completion_signatures()
  {
    return exec::completion_signatures<
      exec::set_value_t(int),
      exec::set_error_t(std::exception_ptr),
      exec::set_stopped_t()
    >{};
  }

  // ...
};

非依存Sender/依存Sender

Senderはその完了シグネチャ集合が確定するタイミングに応じて、下記2種類に区分される。

非依存Sender(non-dependent sender)
オブジェクト構築時点で完了シグネチャ集合が確定しているSender*2。例:justファクトリが生成するSender。非依存Senderを子Senderにもつ標準Senderアダプタが生成するSenderなど。
依存Sender(dependent sender)
Senderと後続Receiverとの接続時(connect)に、Receiver環境(environment)に依存して完了シグネチャ集合が型計算されるSender。execution::dependent_senderコンセプトを満たす。例:Receiver環境を読み取るread_envアルゴリズム(→id:yohhoy:20250612)が生成するSender。

Sender型Sndrの非依存Sender/依存Sender区分は、コンパイル時に静的メンバ関数テンプレートをSndr::get_completion_signatures<Sndr>()形式で呼び出したときにexecution::dependent_sender_error例外を送出*3する(依存Sender)か否か(非依存Sender)で判定される。

Senderクラスでは下記いずれかの静的メンバ関数テンプレートget_completion_signaturesを定義すればよい。いずれも空の引数リストをもち、戻り値型はクラステンプレートexecution::completion_signatures<Sigs...>とする*4。妥当な完了シグネチャ集合を定義できない場合は、任意の例外クラスを送出する*5ことでコンパイルエラーとできる。

// 非依存Senderとして定義
template <class Sndr>
static consteval auto get_completion_signatures();

// 依存Senderとして定義
template <class Sndr, class Env>
static consteval auto get_completion_signatures();

// 型情報に応じて非依存Sender/依存Senderを切替
template <class Sndr, class... Env>
static consteval auto get_completion_signatures();
// 依存Senderとして定義する場合は、Envが空の
// 呼び出し式 get_completion_signatures<Sndr>() に対して
// 例外 execution::dependent_sender_error を送出する

旧P2300R10仕様

提案文書P3557R3採択以前の実行制御ライブラリベース提案P2300R10時点では、Sender型Sndrの完了シグネチャ集合宣言には下記方式がとられていた。

  • 非依存Sender(相当)*6:メンバ型Sndr::completion_signaturesとして完了シグネチャ集合execution::completion_signatures<Sigs...>を定義する。
  • 依存Sender:戻り値型execution::completion_signatures<Sigs...>をもつメンバ関数テンプレートget_completion_signatures(Env)を定義する。SenderオブジェクトsndrとReceiver環境envに対して、decltype(sndr.get_completion_signatures(env))で完了シグネチャ集合をコンパイル時計算する。

P3557R1まではメンバ型completion_signatures定義方式も有効であったが、P3164R4を統合したP3557R2時点で冗長な仕様として削除された経緯がある。

Drop support for specifying a sender's completion signatures with a nested type alias.

P3557R3, Revision History, R2

Finally, since a sender can now use its get_completion_signatures() member function to provide its non-dependent senders, the nested completion_signatures type alias becomes redundant. This paper suggests dropping support for that.

P3164R4 Early Diagnostics for Sender Expressions

関連URL

*1:https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/n5014.pdf

*2:型 Sndr が非依存Senderであることは、式 sender<Sndr> && !dependent_sender<Sndr> で判定可能。

*3:C++26からコンパイル時の例外送出+例外ハンドリング(try-catch)がサポートされる。P3068R6 参照。

*4:仮に適当な型を戻り値型としても execution::get_completion_signatures 仕様により未規定の例外送出動作へと変換される。これは同関数テンプレートの戻り値型制約を満たすための措置。

*5:依存Sender判定に用いられる execution::dependent_sender_error 以外を送出すること。

*6:P2300R10時点では “非依存Sender” 概念は定義されておらず、依存Senderと同様にReceiver接続時まで完了シグネチャ集合の計算および検査が遅延されていた。