yohhoyの日記

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

C++20標準ライブラリ仕様:Constraints/Mandates/Preconditions

C++2a(C++20)標準ライブラリの関数仕様記述で用いられる Constraints/Mandates/Preconditions の違いについてメモ。

  • 現行C++17標準ライブラリの Requires は廃止され、C++2aでは Constraints/Mandates/Preconditions に細分化される。
  • Mandates: 型や定数式に対する必須要件。違反時は ill-formed のためコンパイルエラー。
  • Constraints: 型や定数式に対する制約条件。違反時は関数オーバーロード候補から除外される。“SFINAE-friendly”
  • Preconditions: 引数値やオブジェクト状態に対する事前条件。違反時は実行時エラーや未定義動作(undefined behavior)を引き起こす。
  • C++標準規格では関数仕様のみを定め、標準ライブラリの実現方式には言及しない。
    • 例:Constraintsは requires節*1enable_if*2、constexpr if*3 など任意の仕組みで実現されうる。

例:std::packaged_task<R(ArgTypes...)>のテンプレートコンストラクtemplate<class F> packaged_task(F&& f);定義は、C++17/C++2a標準ライブラリ仕様ではそれぞれ下記の通り記述される。*4

C++17仕様)
Requires: INVOKE<R>(f, t1, t2, ..., tN), where t1, t2, ..., tN are values of the corresponding types in ArgTypes..., shall be a valid expression. Invoking a copy of f shall behave the same as invoking f.
Remarks: This constructor shall not participate in overload resolution if decay_t<F> is the same type as packaged_task<R(ArgTypes...)>.

C++2a仕様)
Constraints: remove_cvref_t<F> is not the same type as packaged_task<R(ArgTypes...)>.
Mandates: is_invocable_r_v<R, F&, ArgTypes...> is true.
Preconditions: Invoking a copy of f behaves the same as invoking f.

提案文書(PDF)P0788R3, §3 Proposed principles and practices より一部引用(下線部は強調)。注:C++2aではContracts導入が見送られたため*5Expects:Ensures: はそれぞれ Preconditions:Postconditions: が対応する。

I. Let's not recycle a Requires: element to mean something other than what it means today.

  • a) Let's instead adopt new elements, described below, to specify the Library requirements that are (or that should have been) specified via our current Requires: elements. [(snip)]
  • (snip)


II. Let's introduce a new Constraints: element.

  • a) Let's use this Constraints: element to specify the compile-time circumstances that must be satisfied in order that the corresponding Library component will be compiled. [(snip)]
  • b) Let's ensure that unsatisfied Constraints: not produce any diagnostic in and of themselves.
    [This obviates the need for specification wording such as "shall not participate in overload resolution." Note that a consequential diagnostic might still result: for example, overload resolution might find no viable candidates due to unsatisfied constraints and/or other factors.]
  • c) Let's introduce a new Mandates: element to specify the compile-time circumstances under which, when unsatisfied, an implementation must produce a diagnostic.
    [(snip)]
    [This element obviates the need for any "is ill-formed" specifications. For example, in [pair.astuple]/1 we today find the specification "Requires: I < 2. The program is ill-formed if I is out of bounds." Under the present proposal, this would be simplified to "Mandates: I < 2."]


III. Let's introduce a new Expects: element.

  • a) Let's use this Expects: element to specify the circumstances that must be satisfied to avoid undefined behavior when the corresponding Library component is invoked.
    [Industry-wide, such requirements have come to be known as preconditions, but the Contracts proposals [P0542R1] seem to have chosen "expects" as their preferred term of art; it seems better to have a single term and use it consistently.]
  • (snip)


IV. Let's avoid any specification that demands any particular technology by which implementations must comply with Library specifications.

  • a) Let's permit an implementation to use a requires-clause, an enable_if, a constexpr if, or any other technology or combination of technologies to meet Constraints: specifications.
  • b) Let's permit an implementation to use static_assert and/or any other technologies to meet Mandates: specifications.
  • c) Let's permit an implementation to use Contracts attributes [P0542R1] and/or any other technologies to meet Expects: and Ensures: specifications.
  • d) Let's consider user code that relies on any specific technology on the part of an implementation to be ill-formed, with no diagnostic required.

C++17仕様

C++17 20.4.1.4/p3-4より一部引用。

3 Descriptions of function semantics contain the following elements (as appropriate):

  • Requires: the preconditions for calling the function
  • (snip)

4 (snip) If F's semantics specifies a Requires: element, then that requirement is logically imposed prior to the equivalent-to semantics. (snip)

C++2a仕様

C++2a DIS(N4861) 16.4.1.4/p3より一部引用。

3 Descriptions of function semantics contain the following elements (as appropriate):

  • Constraints: the conditions for the function's participation in overload resolution (12.4). [Note: Failure to meet such a condition results in the function's silent non-viability. --end note] [Example: An implementation might express such a condition via a constraint-expression (13.5.2). --end example]
  • Mandates: the conditions that, if not met, render the program ill-formed. [Example: An implementation might express such a condition via the constant-expression in a static_assert-declaration (9.1). If the diagnostic is to be emitted only after the function has been selected by overload resolution, an implementation might express such a condition via a constraint-expression (13.5.2) and also define the function as deleted. --end example]
  • Preconditions: the conditions that the function assumes to hold whenever it is called.
  • (snip)

4 (snip) If F's semantics specifies any Constraints or Mandates elements, then those requirements are logically imposed prior to the equivalent-to semantics. (snip)

関連URL