最終更新日時(UTC):
が更新

履歴 編集

named requirement
<concepts>

::INVOKE(C++11)

C++における関数呼び出しという性質を抽象化しまとめた、仮想操作 INVOKE を定義する。

  • C++17からは、仮想操作 INVOKE を実体化したstd::invoke関数テンプレートが提供される。
  • C++23からは、仮想操作 INVOKE<R> を実体化したstd::invoke_r関数テンプレートが提供される。

用語定義

  • call-signature とは、戻り値型に続けて丸カッコの中に0個以上の引数型を並べたものである。 cf. int ( std::string, int )
  • callable-type とは、関数呼び出し演算子を適用できる型 ( 関数、関数への参照、関数へのポインタ、operator () をオーバーロードした型もしくはそれを(直接または間接的に) public 継承した型 ) もしくはメンバへのポインタ型を指す。
  • callable-object は、 callable-type 型のオブジェクトである。
  • call-wrapper-type は、 callable-object を保持し、自身に対する関数呼び出し操作が行われたとき、保持しているオブジェクトに委譲する。
  • call-wrapper は、 call-wrapper-type 型のオブジェクトである。
  • target-object とは、 callable-object に保持されているオブジェクトのことである。

要件(C++14まで)

  1. 仮想操作 INVOKE(f, t1, t2, ..., tN) を次のように定義する。
    • f が型 T のメンバ関数へのポインタであり、 t1 が T 型のオブジェクトあるいは T または T を継承した型への参照であるとき、 (t1.*f)(t2, ..., tN) と同じ効果を持つ。
    • f が型 T のメンバ関数へのポインタであり、 t1 が上記の条件に当てはまらない場合、((*t1).*f)(t2, ..., tN) と同じ効果を持つ。
    • N == 1 で、f が型 T のメンバオブジェクトへのポインタであり、t1T 型のオブジェクトあるいは T または T を継承した型への参照であるとき、 t1.*f と同じ効果を持つ。
    • N == 1 で、f が型 T のメンバオブジェクトへのポインタであり、t1 が上記の条件に当てはまらない場合、 (*t1).*f と同じ効果を持つ。
    • 上記の条件のどれにも当てはまらない場合、 f(t1, t2, ..., tN) と同じ効果を持つ。
  2. INVOKE(f, t1, t2, ..., tN, R) を、 INVOKE(f, t1, t2, ..., tN) の実行結果の戻り値が型 R に暗黙的に変換されること、と定義する。
  3. call-wrapperweak-result-type を用意している場合、メンバ型 result_typetarget-object の型 T に応じて次のように定義される。
    • T が関数へのポインタ型であるとき、 result_typeT の戻り値型と等しい。
    • T がメンバ関数へのポインタ型であるとき、 result_typeT の戻り値型と等しい。
    • Tresult_type という名前のメンバ型を持つとき、 result_typeT::result_type と等しい。
    • どの条件にも当てはまらない場合、 result_type は定義されない。
  4. すべての call-wrapper は、MoveAssignable でなければならない。

要件(C++17)

  1. 仮想操作 INVOKE(f, t1, t2, ..., tN) を次のように定義する。
    • f が型 T のメンバ関数へのポインタであり、is_base_of_v<T,decay_t<decltype(t1)>> == truet1T または T を継承した型のオブジェクト/参照)であるとき、 (t1.*f)(t2, ..., tN) と同じ効果を持つ。
    • f が型 T のメンバ関数へのポインタであり、decay_t<decltype(t1)>reference_wrapper<T>t1reference_wrapperの特殊化)であるとき、 (t1.get().*f)(t2, ..., tN) と同じ効果を持つ。
    • f が型 T のメンバ関数へのポインタであり、 t1 が上記の条件に当てはまらない場合(例えば、t1がTのポインタ)、((*t1).*f)(t2, ..., tN) と同じ効果を持つ。
    • N == 1 で、f が型 T のメンバオブジェクトへのポインタであり、is_base_of_v<T,decay_t<decltype(t1)>> == truet1T または T を継承した型のオブジェクト/参照)であるとき、 t1.*f と同じ効果を持つ。
    • N == 1 で、f が型 T のメンバオブジェクトへのポインタであり、decay_t<decltype(t1)>reference_wrapper<T>t1reference_wrapperの特殊化)であるとき、 t1.get().*f と同じ効果を持つ。
    • N == 1 で、f が型 T のメンバオブジェクトへのポインタであり、t1 が上記の条件に当てはまらない場合(例えば、t1がTのポインタ)、 (*t1).*f と同じ効果を持つ。
    • 上記の条件のどれにも当てはまらない場合、 f(t1, t2, ..., tN) と同じ効果を持つ。
  2. INVOKE<R>(f, t1, t2, ..., tN) を次のように定義する。
    • Rvoidかそのcv修飾の場合は、static_cast<void>(INVOKE(f, t1, t2, ..., tN))
    • それ以外の場合は、INVOKE(f, t1, t2, ..., tN) の実行結果の戻り値が型 R に暗黙的に変換されること。
  3. すべての call-wrapper は、MoveConstructible でなければならない。

要件(C++20)

  1. 仮想操作 INVOKE(f, t1, t2, ..., tN) を次のように定義する。
    • f が型 T のメンバ関数へのポインタであり、is_base_of_v<T,remove_cvref_t<decltype(t1)>> == truet1T または T を継承した型のオブジェクト/参照)であるとき、 (t1.*f)(t2, ..., tN) と同じ効果を持つ。
    • f が型 T のメンバ関数へのポインタであり、remove_cvref_t<decltype(t1)>reference_wrapper<T>t1reference_wrapperの特殊化)であるとき、 (t1.get().*f)(t2, ..., tN) と同じ効果を持つ。
    • f が型 T のメンバ関数へのポインタであり、 t1 が上記の条件に当てはまらない場合(例えば、t1がTのポインタ)、((*t1).*f)(t2, ..., tN) と同じ効果を持つ。
    • N == 1 で、f が型 T のメンバオブジェクトへのポインタであり、is_base_of_v<T,remove_cvref_t<decltype(t1)>> == truet1T または T を継承した型のオブジェクト/参照)であるとき、 t1.*f と同じ効果を持つ。
    • N == 1 で、f が型 T のメンバオブジェクトへのポインタであり、remove_cvref_t<decltype(t1)>reference_wrapper<T>t1reference_wrapperの特殊化)であるとき、 t1.get().*f と同じ効果を持つ。
    • N == 1 で、f が型 T のメンバオブジェクトへのポインタであり、t1 が上記の条件に当てはまらない場合(例えば、t1がTのポインタ)、 (*t1).*f と同じ効果を持つ。
    • 上記の条件のどれにも当てはまらない場合、 f(t1, t2, ..., tN) と同じ効果を持つ。
  2. INVOKE<R>(f, t1, t2, ..., tN) を次のように定義する。
    • Rvoidかそのcv修飾の場合は、static_cast<void>(INVOKE(f, t1, t2, ..., tN))
    • それ以外の場合は、INVOKE(f, t1, t2, ..., tN) の実行結果の戻り値が型 R に暗黙的に変換されること。
  3. すべての call-wrapper は、Cpp17MoveConstructible かつ Cpp17Destructible でなければならない。

要件(C++23差分)

C++20 における 2. について、次の文言を項目の最後に追加する。この変更は、Rが参照かつINVOKEの実行結果がRに束縛されることで寿命が延長される場合にダングリング参照が作成されてしまう事例を検出するための要件である。

まとめ

第1引数がメンバ関数へのポインタの場合でも非静的メンバデータへのポインタの場合でも,第2引数がクラスオブジェクトへの参照の場合でもポインタの場合でもポインタっぽいものの場合でも,なんか知らんけどそれっぽく上手くいく ように取り計らった操作のことである。

関連項目

参照