namespace std {
template<class Token>
concept stoppable_token;
}
概要
stoppable_tokenは、型Tokenが停止トークンとしての基本的なインタフェースを提供することを表すコンセプトである。
要件
まず、説明専用クラステンプレートcheck-type-alias-existsを以下のように定義する。
template<template<class> class>
struct check-type-alias-exists;
stoppable_tokenコンセプトは、以下のように定義される。
template<class Token>
concept stoppable_token =
requires (const Token tok) {
typename check-type-alias-exists<Token::template callback_type>;
{ tok.stop_requested() } noexcept -> same_as<bool>;
{ tok.stop_possible() } noexcept -> same_as<bool>;
{ Token(tok) } noexcept;
} &&
copyable<Token> &&
equality_comparable<Token> &&
swappable<Token>;
モデル
説明用の変数t, uを、同一の停止状態を参照する別々なToken型オブジェクトとする。
型Tokenが以下を満たす場合に限って、型Tokenはstoppable_tokenのモデルである。
SPをt.stop_possible()がfalseとなる評価としたとき、SPより後に発生するu.stop_possible()やu.stop_requested()の評価はfalseであること。SRをt.stop_requested()がtrueとなる評価としたとき、SRより後に発生するu.stop_possible()やu.stop_requested()の評価はtrueであること。stoppable-callback-for<CallbackFn, Token, Initialize>を満たす任意の型CallbackFnおよび型Initializeが、stoppable-callback-for<CallbackFn, Token, Initializer>のモデルであること。tが停止状態を持たない(disengaged)とき、t.stop_possible()やt.stop_requested()の評価がfalseであること。tとuが同一の停止状態を参照するか共に停止状態を持たないときt == uがtrueであり、それ以外のときはfalseであること。request_stop,stop_requested,stop_possibleメンバ関数の呼び出しはデータ競合を引き起こさない。
ここで、説明専用コンセプトstoppable-callback-forを以下のように定義する。
template<class CallbackFn, class Token, class Initializer = CallbackFn>
concept stoppable-callback-for =
invocable<CallbackFn> &&
constructible_from<CallbackFn, Initializer> &&
requires { typename stop_callback_for_t<Token, CallbackFn>; } &&
constructible_from<stop_callback_for_t<Token, CallbackFn>, const Token&, Initializer>;
説明用のinitをsame_as<decltype(init), Initializer>を満たす式、型SCBをstop_callback_for_t<Token, CallbackFn>とする。
stoppable-callback-for<CallbackFn, Token, Initializer>のモデルとなるには、下記を満たすこと。
- 次のコンセプトのモデルであること。
constructible_from<SCB, Token, Initializer>constructible_from<SCB, Token&, Initializer>constructible_from<SCB, const Token, Initializer>
- 説明用の
scbをSCB型オブジェクト、callback_fnをscbに関連付けられたCallbackFn型のコールバック関数とする。引数tとinitからの直接非リスト初期化scbは、次のように停止可能コールバック登録(stoppable callback registration)を実行すること。t.stop_possible() == trueのとき、callback_fnがinitで直接初期化される。scb構築が送出する例外は、initからのcallback_fn構築で送出された例外のみ。- コールバック呼び出し
std::forward<CallbackFn>(callback_fn)()は、次のようにtに関連する停止状態に登録されること。- 登録時点で
t.stop_requested()がfalseに評価されるとき、コールバック呼び出しは停止状態のコールバックリストに追加され、停止状態に停止要求が行われたたときにstd::forward<CallbackFn>(callback_fn)()が評価される。 - そうでなければ、
scbコンストラクタを実行したスレッド上でstd::forward<CallbackFn>(callback_fn)()が即時実行され、コールバック呼び出しはリストに追加されない。
- 登録時点で
t.stop_possible() == falseのとき、callback_fnの初期化によるscb初期化には要求が課されない。
scbの破棄は、次のように停止可能コールバック登録解除(stoppable callback deregistration)を実行すること。scbコンストラクタがtの停止状態にコールバック呼び出しを登録していなければ、停止可能コールバック登録解除はcallback_fn破棄以外の効果を持たない。- そうでなければ、関連する停止状態から
callback_fnの呼び出しが除外されること。 callback_fnが別スレッド上で並行実行中の場合、当該callback_fn呼び出しから戻るまで停止可能コールバック登録解除はブロックされる。このcallback_fn呼び出しからの戻りはcallback_fnの破棄よりも確実に前に発生する。callback_fnが現在のスレッド上で実行中の場合、デストラクタはcallback_fnからの戻りを待機してブロックしてはいけない。- 停止可能コールバック登録解除は、同じ停止状態に登録された他のコールバック呼び出しの完了をブロックしてはいけない。
- 停止可能コールバック登録解除は
callback_fnを破棄すること。
バージョン
言語
- C++26
処理系
- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??