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

履歴 編集

class template
<functional>

std::move_only_function(C++23)

namespace std {
  template<class... S>
  class move_only_function; // 宣言のみ

  template<class R, class... ArgTypes>
  class move_only_function<R(ArgTypes...) /*cv*/ /*ref*/ noexcept(/*noex*/)>;
}

概要

move_only_functionクラステンプレートは、パラメータの型リストArgTypes...、戻り値の型Rに合致する、あらゆる関数ポインタ、関数オブジェクト、メンバ関数ポインタ、メンバ変数ポインタを保持できるクラスである。

下記全ての組み合わせ(12種類)に対して、クラステンプレートの部分特殊化が提供される。

  • CV修飾子 cv : const, CV修飾無し
  • 参照修飾子 ref : &, &&, 参照修飾無し
  • noexcept例外指定 noex : true, false

functionとの比較

std::functionと比べて、std::move_only_functionは下記の特徴をもつ。

  • ムーブのみ対応。コピー不可。
  • 関数型のCV修飾/参照修飾/noexcept例外指定をサポートする。
    • const性などを正しく伝搬することでバグ発生リスクを軽減する
  • target_type型とtarget()を提供しない。
    • 実行時型情報(RTTI)非依存
  • 関数呼び出しは強い事前条件を持つ。
    • 関数呼び出し時のnullチェックが要求されない
  • クラステンプレート引数の推論補助を提供しない。

メンバ関数

名前 説明 対応バージョン
(constructor) コンストラクタ C++23
(destructor) デストラクタ C++23
operator= 代入演算子 C++23
swap 他のmove_only_functionオブジェクトと中身を入れ替える C++23
operator bool 関数呼び出しが可能か調べる C++23
operator() 関数呼び出し C++23

メンバ型

名前 説明 対応バージョン
result_type 関数の戻り値の型(テンプレートパラメータR) C++23

非メンバ関数

名前 説明 対応バージョン
operator== 等値比較 C++23
operator!= 非等値比較 C++23
swap 2つのmove_only_functionオブジェクトを入れ替える C++23

例1: 基本の使い方

#include <functional>
#include <iostream>

int add(int x) { return x + 1; }

int main()
{
  // 関数を代入
  std::move_only_function<int(int)> f = add;

  // 関数オブジェクトを代入
  f = [](int x) { return x + 1; };

  // 保持している関数を呼び出す
  int result = f(1);
  std::cout << result << std::endl;
}

出力

2

例2: const性の伝搬

#include <functional>
#include <iostream>
#include <string>
#include <utility>

struct Functor {
  std::string operator()() {
    return "non-const";
  }
  std::string operator()() const {
    return "const";
  }
};

int main()
{
  std::cout << "-- move_only_function" << std::endl;
        std::move_only_function<std::string(void)>       mof1 = Functor{};
  const std::move_only_function<std::string(void)>       mof2 = Functor{}; // (呼び出し時に不適格)
        std::move_only_function<std::string(void) const> mof3 = Functor{};
  const std::move_only_function<std::string(void) const> mof4 = Functor{};
  std::cout << "mof1: " << mof1() << std::endl;
//std::cout << "mof2: " << mof2() << std::endl; // 不適格
  std::cout << "mof3: " << mof3() << std::endl;
  std::cout << "mof4: " << mof4() << std::endl;

  std::cout << "-- function" << std::endl;
        std::function<std::string(void)>       fn1 = Functor{};
  const std::function<std::string(void)>       fn2 = Functor{};
//      std::function<std::string(void) const> fn3 = Functor{}; // 不適格
//const std::function<std::string(void) const> fn4 = Functor{}; // 不適格
  std::cout << "fn1: " << fn1() << std::endl;
  std::cout << "fn2: " << fn2() << std::endl;
}

出力

-- move_only_function
mof1: non-const
mof3: const
mof4: const
-- function
fn1: non-const
fn2: non-const

例3: 左辺値/右辺値の伝搬

#include <functional>
#include <iostream>
#include <string>
#include <utility>

struct Functor {
  std::string operator()() & {
    return "L-val";
  }
  std::string operator()() && {
    return "R-val";
  }
};

int main()
{
  std::cout << "-- move_only_function" << std::endl;
  std::move_only_function<std::string(void)>    mof1 = Functor{};
  std::move_only_function<std::string(void) &&> mof2 = Functor{};
  std::cout << "mof1/L-val: " << mof1()            << std::endl;
  std::cout << "mof1/R-val: " << std::move(mof1)() << std::endl;
//std::cout << "mof2/L-val: " << mof2()            << std::endl; // 不適格
  std::cout << "mof2/R-val: " << std::move(mof2)() << std::endl;

  std::cout << "-- function" << std::endl;
  std::function<std::string(void)>    fn1 = Functor{};
//std::function<std::string(void) &&> fn2 = Functor{}; // 不適格
  std::cout << "fn1/L-val: " << fn1()            << std::endl;
  std::cout << "fn1/R-val: " << std::move(fn1)() << std::endl;
}

出力

-- move_only_function
mof1/L-val: L-val
mof1/R-val: L-val
mof2/R-val: R-val
-- function
fn1/L-val: L-val
fn1/R-val: L-val

例4: noexcept指定の伝搬

#include <functional>

void func() {}
void func_noex() noexcept {}

int main()
{
  std::move_only_function<void(void)>          mof1 = func;
  std::move_only_function<void(void)>          mof2 = func_noex;
//std::move_only_function<void(void) noexcept> mof3 = func; // 不適格
  std::move_only_function<void(void) noexcept> mof4 = func_noex;
  static_assert(not noexcept(mof1()));
  static_assert(not noexcept(mof2()));
  static_assert(    noexcept(mof4()));

  std::function<void(void)>          fn1 = func;
  std::function<void(void)>          fn2 = func_noex;
//std::function<void(void) noexcept> fn3 = func;      // 不適格
//std::function<void(void) noexcept> fn4 = func_noex; // 不適格
  static_assert(not noexcept(fn1()));
  static_assert(not noexcept(fn2()));
}

出力

バージョン

言語

  • C++23

処理系

関連項目

参照