diff --git a/lang/cpp23.md b/lang/cpp23.md index 48d4410f46..2263b8a0a8 100644 --- a/lang/cpp23.md +++ b/lang/cpp23.md @@ -188,7 +188,7 @@ C++23とは、2023年中に改訂される予定の、C++バージョンの通 ### 関数オブジェクト - [`std::invoke()`](/reference/functional/invoke.md)の戻り値型を指定するバージョンである[`std::invoke_r()`](/reference/functional/invoke_r.md)を追加 -- ムーブのみ可能な[`std::function`](/reference/functional/function.md)クラスと等価な機能をもつ[`std::move_only_function`](/reference/functional/move_only_function.md.nolink)クラスを追加 +- [`std::function`](/reference/functional/function.md)クラスと等価な機能をもつ、ムーブのみ可能な[`std::move_only_function`](/reference/functional/move_only_function.md)クラスを追加 - ユーザー定義のRangeアダプタがパイプライン演算子 `|` をサポートしやすくするために、末尾から引数を束縛する[`std::bind_back()`](/reference/functional/bind_back.md.nolink)関数を追加 diff --git a/reference/functional/function.md b/reference/functional/function.md index 9e39efb429..27f8027020 100644 --- a/reference/functional/function.md +++ b/reference/functional/function.md @@ -113,6 +113,11 @@ int main() ### 言語 - C++11 + +## 関連項目 +- [`move_only_function`](move_only_function.md) + + ## 参照 - [P0302R1 Removing Allocator Support in `std::function` (rev 1)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0302r1.html) - [P0005R4 Adopt `not_fn` from Library Fundamentals 2 for C++17](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0005r4.html) diff --git a/reference/functional/move_only_function.md b/reference/functional/move_only_function.md new file mode 100644 index 0000000000..ebd0db2017 --- /dev/null +++ b/reference/functional/move_only_function.md @@ -0,0 +1,99 @@ +# move_only_function +* functional[meta header] +* class template[meta id-type] +* std[meta namespace] +* cpp23[meta cpp] + +```cpp +namespace std { + template class move_only_function; // 宣言のみ + + template + class move_only_function; +} +``` + +## 概要 +`move_only_function`クラステンプレートは、パラメータの型リスト`ArgTypes...`、戻り値の型`R`に合致する、あらゆる関数ポインタ、関数オブジェクト、メンバ関数ポインタ、メンバ変数ポインタを保持できるクラスである。 + +下記全ての組み合わせ(12種類)についてクラステンプレートの部分特殊化が提供される。 + +- CV修飾子 *cv* : `const`, CV修飾無し +- 参照修飾子 *ref* : `&`, `&&`, 参照修飾無し +- noexcept例外指定 *noex* : `true`, `false` + + +## メンバ関数 +### 構築・破棄 + +| 名前 | 説明 | 対応バージョン | +|-----------------|----------------|----------------| +| [`(constructor)`](move_only_function/op_constructor.md) | コンストラクタ | C++23 | +| [`(destructor)`](move_only_function/op_destructor.md) | デストラクタ | C++23 | +| [`operator=`](move_only_function/op_assign.md) | 代入演算子 | C++23 | +| [`swap`](move_only_function/swap.md) | 他の`move_only_function`オブジェクトと中身を入れ替える | C++23 | +| [`operator bool`](move_only_function/op_bool.md) | 関数呼び出しが可能か調べる | C++23 | +| [`operator()`](move_only_function/op_call.md) | 関数呼び出し | C++23 | + + +## メンバ型 + +| 名前 | 説明 | 対応バージョン | +|-----------------|----------------|----------------| +| `result_type` | 関数の戻り値の型(テンプレートパラメータ`R`) | C++23 | + +## 非メンバ関数 + +| 名前 | 説明 | 対応バージョン | +|-----------------|----------------|----------------| +| [`operator==`](move_only_function/op_equal.md) | 等値比較 | C++23 | +| [`operator!=`](move_only_function/op_not_equal.md) | 非等値比較 | C++23 | +| [`swap`](move_only_function/swap_free.md) | 2つの`move_only_function`オブジェクトを入れ替える | C++23 | + + +## 例 +```cpp example +#include +#include + +int add(int x) { return x + 1; } + +int main() +{ + // 関数を代入 + std::move_only_function f = add; + + // 関数オブジェクトを代入 + f = [](int x) { return x + 1; }; + + // 保持している関数を呼び出す + int result = f(1); + std::cout << result << std::endl; +} +``` +* std::move_only_function[color ff0000] +* f(1)[link move_only_function/op_call.md] + +### 出力 +``` +1 +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`function`](function.md) + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) diff --git a/reference/functional/move_only_function/op_assign.md b/reference/functional/move_only_function/op_assign.md new file mode 100644 index 0000000000..2990e70d90 --- /dev/null +++ b/reference/functional/move_only_function/op_assign.md @@ -0,0 +1,69 @@ +# operator= +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +move_only_function& operator=(move_only_function&& f); // (1) + +move_only_function& operator=(nullptr_t); noexcept; // (2) + +template +move_only_function& operator=(F&& f); // (3) +``` + +## 効果 +- (1) : ムーブ代入。[`move_only_function`](op_constructor.md)`(`[`std::move`](/reference/utility/move.md)`(f)).`[`swap`](swap.md)`(*this)` +- (2) : `*this`が有効な関数ポインタ、メンバポインタ、もしくは関数オブジェクトを持っている場合、それを解放する。 +- (3) : [`move_only_function`](op_constructor.md)`(`[`std::forward`](/reference/utility/forward.md)`(f)).`[`swap`](swap.md)`(*this)` + + +## 戻り値 +`*this` + + +## 例外 +- (2) : 投げない + + +## 例 +```cpp example +#include +#include + +int ident(int x) { return x; } + +int main() +{ + std::move_only_function f; + + // 関数を代入 + f = ident; + + int result = f(1); + std::cout << result << std::endl; +} +``` +* f(1)[link op_call.md] + +### 出力 +``` +1 +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) diff --git a/reference/functional/move_only_function/op_bool.md b/reference/functional/move_only_function/op_bool.md new file mode 100644 index 0000000000..c6cfaad762 --- /dev/null +++ b/reference/functional/move_only_function/op_bool.md @@ -0,0 +1,58 @@ +# operator bool +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +explicit operator bool() const noexcept; +``` + +## 概要 +関数呼び出しが可能か調べる。 + + +## 戻り値 +呼び出す関数を持っていれば`true`、そうでなければ`false`を返す。 + + +## 例 +```cpp example +#include +#include + +int ident(int x) { return x; } + +int main() +{ + std::move_only_function f = ident; + + if (f) { + std::cout << "not empty" << std::endl; + } + else { + std::cout << "empty" << std::endl; + } +} +``` + +### 出力 +``` +not empty +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) diff --git a/reference/functional/move_only_function/op_call.md b/reference/functional/move_only_function/op_call.md new file mode 100644 index 0000000000..e72ca00699 --- /dev/null +++ b/reference/functional/move_only_function/op_call.md @@ -0,0 +1,67 @@ +# operator() +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +R operator()(ArgTypes... args) /*cv*/ /*ref*/ noexcept(/*noex*/); +``` + +## 概要 +関数を呼び出す。 + +CV修飾子 *cv*, 参照修飾子 *ref*, noexcept例外指定 *noex* は[`move_only_function`](../move_only_function.md)に指定するテンプレートパラメータ`R(ArgTypes...)`部と等しい。 + + +## 事前条件 +`*this`は関数ポインタまたは関数オブジェクトを保持していること。 + + +## 効果 +`*this`が保持している`F`型の関数ポインタまたは関数オブジェクト`f`に対して、[`INVOKE`](/reference/concepts/Invoke.md)`(static_cast(f),` [`std::forward`](/reference/utility/forward.md)`(args)...)`を行う。 + + +## 戻り値 +`R`型が`void`の場合は何も返さない。そうでなければ、関数呼び出しの戻り値を返す。 + + +## 例 +```cpp example +#include +#include + +int ident(int x) +{ return x; } + +int main() +{ + std::move_only_function f = ident; + + // 関数呼び出し : 保持しているident()関数を呼び出す + int result = f(1); + + std::cout << result << std::endl; +} +``` + +### 出力 +``` +1 +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) diff --git a/reference/functional/move_only_function/op_constructor.md b/reference/functional/move_only_function/op_constructor.md new file mode 100644 index 0000000000..5a13d4bcdd --- /dev/null +++ b/reference/functional/move_only_function/op_constructor.md @@ -0,0 +1,188 @@ +# コンストラクタ +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +move_only_function() noexcept; // (1) +move_only_function(nullptr_t) noexcept; // (2) +move_only_function(move_only_function&&) noexcept; // (3) + +template move_only_function(F&&); // (4) + +template +explicit move_only_function(in_place_type_t, Args&&...); // (5) + +template +explicit move_only_function(in_place_type_t, initializer_list, Args&&...); // (6) +``` +* in_place_type_t[link /reference/utility/in_place_type_t.md] + +## 概要 +`move_only_function`オブジェクトを構築する。 + + +`move_only_function`クラステンプレートパラメータのnoexcept例外指定 *noex* 特殊化に応じて、説明用の`bool`型テンプレート定数`is-callable-from`を下記のように定義する : +- *noex* が`true`のとき : [`is_nothrow_invocable_r_v`](/reference/type_traits/is_nothrow_invocable_r.md)` &&` [`is_nothrow_invocable_r_v`](/reference/type_traits/is_nothrow_invocable_r.md)`` +- *noex* が`false`のとき : [`is_invocable_r_v`](/reference/type_traits/is_invocable_r.md)` &&` [`is_invocable_r_v`](/reference/type_traits/is_invocable_r.md)`` + + +## テンプレートパラメータ制約 +- (4) : `VT`型を`decay_t`としたとき + - `remove_cvref_t`が`move_only_function`と同一型ではなく、かつ + - `remove_cvref_t`が`in_place_type_t`の特殊化ではなく、かつ + - `is-callable-from`が`true`であること +- (5) : `VT`型を`decay_t`としたとき + - [`is_constructible_v`](/reference/type_traits/is_constructible.md)``が`true`であり、かつ + - `is-callable-from`が`true`であること +- (6) : `VT`型を`decay_t`としたとき + - [`is_constructible_v`](/reference/type_traits/is_constructible.md)`&, Args...>`が`true`であり、かつ + - `is-callable-from`が`true`であること + + +## 適格要件 +- (4) : `VT`型を`decay_t`としたとき、[`is_constructible_v`](/reference/type_traits/is_constructible.md)``が`true`であること。 +- (5), (6) : `decay_t`が`T`と同一型であること。 + + +## 事前条件 +- (4) : `VT`型を`decay_t`としたとき + - `VT`がCpp17Destructible要件を満たすこと。 + - [`is_move_construtible_v`](/reference/type_traits/is_move_constructible.md)``が`true`の場合、`VT`がCpp17MoveConstructible要件を満たすこと。 +- (5), (6) : `VT`型を`decay_t`としたとき + - `VT`がCpp17Destructible要件を満たすこと。 + - [`is_move_construtible_v`](/reference/type_traits/is_move_constructible.md)``が`true`の場合、`VT`がCpp17MoveConstructible要件を満たすこと。 + + +## 効果 +- (1), (2) : 関数を持たない空の`move_only_function`オブジェクトを構築する。この方法で構築した後、[`operator bool`](op_bool.md)は`false`を返す。 +- (3) : `f`が保持する状態を`*this`に移動する。移動された後の`f`は、未規定な値を持つ有効な状態となる。 +- (4) : `*this`の格納オブジェクトを + - `f`が関数ポインタ型、メンバ関数ポインタ型、メンバ変数ポインタ型いずれかのヌルポインタ値の場合、値を保持しない。 + - `remove_cvref_t`が`move_only_function`の特殊化であり、かつ値を保持していない場合、値を保持しない。 + - そうでなければ、`*this`が保持する`VT`型の格納オブジェクトを、`std::forward(f)`で直接非リスト初期化する。 +- (5) : `*this`が保持する`VT`型の格納オブジェクトを、`std::forward(args)...`で直接非リスト初期化する。 +- (6) : `*this`が保持する`VT`型の格納オブジェクトを、`ilist, std::forward(args)...`で直接非リスト初期化する。 + + +## 例外 +- (1), (2), (3) : 投げない +- (4), (5), (6) : 格納オブジェクトの初期化から例外が投げられる可能性がある。`VT`が関数ポインタまたは[`reference_wrapper`](/reference/functional/reference_wrapper.md)の特殊化いずれでもなければ、`bad_alloc`例外が投げられる可能性がある。 + + +## 例 +```cpp example +#include +#include +#include + +struct ident_functor { + int operator()(int x) const + { return x; } +}; + +int ident_func(int x) +{ return x; } + +struct X { + int value; + X() : value(3) {} + + int ident_member_func(int x) const + { return x; } +}; + +int main() +{ + // (1) + // デフォルトコンストラクタ + // 空のmove_only_functionオブジェクトを作る + { + std::move_only_function f; + assert(!f); + } + + // (2) + // ヌルポインタを受け取るコンストラクタ + // デフォルトコンストラクタと同様、空のmove_only_functionオブジェクトを作る + { + std::move_only_function f = nullptr; + assert(!f); + } + + // (3) + // ムーブ構築 + { + std::move_only_function f = ident_functor(); + std::move_only_function g = std::move(f); + + int result = g(1); + std::cout << "(3) : " << result << std::endl; + } + + // (4) + // 関数ポインタを受け取って構築 + { + std::function f = ident_func; + + int result = f(1); + std::cout << "(4) function pointer : " << result << std::endl; + } + + // (4) + // 関数オブジェクトを受け取って構築 + { + std::function f = ident_functor(); + + int result = f(1); + std::cout << "(4) function object : " << result << std::endl; + } + + // (4) + // メンバ関数ポインタを受け取った構築 + { + std::function f = &X::ident_member_func; + + X x; + int result = f(x, 1); + std::cout << "(4) member function pointer : " << result << std::endl; + } + + // (4) + // メンバ変数ポインタを受け取った構築 + { + std::function f = &X::value; + + X x; + int result = f(x); + std::cout << "(4) member variable pointer : " << result << std::endl; + } +} +``` +* std::move[link /reference/utility/move.md] + +### 出力 +``` +(3) : 1 +(4) function pointer : 1 +(4) function object : 1 +(4) member function pointer : 1 +(4) member variable pointer : 3 +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) diff --git a/reference/functional/move_only_function/op_destructor.md b/reference/functional/move_only_function/op_destructor.md new file mode 100644 index 0000000000..abd3afe51f --- /dev/null +++ b/reference/functional/move_only_function/op_destructor.md @@ -0,0 +1,36 @@ +# デストラクタ +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +~move_only_function(); +``` + +## 概要 +`move_only_function`オブジェクトを破棄する。 + + +## 効果 +`*this`が有効な関数ポインタ、メンバポインタ、もしくは関数オブジェクトを持っている場合、その関数を解放する。 + + +## 例外 +投げない + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) diff --git a/reference/functional/move_only_function/op_equal.md b/reference/functional/move_only_function/op_equal.md new file mode 100644 index 0000000000..f885652e71 --- /dev/null +++ b/reference/functional/move_only_function/op_equal.md @@ -0,0 +1,66 @@ +# operator== +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function template[meta id-type] +* cpp23[meta cpp] + +```cpp +friend bool operator==(const move_only_function& f, nullptr_t) noexcept; // (1) + +// (1)により、以下のオーバーロードが使用可能になる +friend bool operator==(nullptr_t, const move_only_function& f) noexcept; // (2) +``` +* nullptr_t[link /reference/cstddef/nullptr_t.md] + +## 概要 +等値比較する。 + + +## 戻り値 +`!f` + + +## 例 +```cpp example +#include +#include + +int ident(int x) { return x; } + +int main() +{ + std::move_only_function f; + + if (f == nullptr) { + std::cout << "empty" << std::endl; + } + + f = ident; + if (f == nullptr) {} + else { + std::cout << "not empty" << std::endl; + } +} +``` + +### 出力 +``` +empty +not empty +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) diff --git a/reference/functional/move_only_function/op_not_equal.md b/reference/functional/move_only_function/op_not_equal.md new file mode 100644 index 0000000000..b1f6ba926e --- /dev/null +++ b/reference/functional/move_only_function/op_not_equal.md @@ -0,0 +1,66 @@ +# operator!= +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function template[meta id-type] +* cpp23[meta cpp] + +```cpp +// operator==により、以下のオーバーロードが使用可能になる +bool operator!=(const move_only_function& f, nullptr_t) noexcept; // (1) + +bool operator!=(nullptr_t, const move_only_function& f) noexcept; // (2) +``` +* nullptr_t[link /reference/cstddef/nullptr_t.md] + +## 概要 +非等値比較する。 + + +## 戻り値 +`static_cast(f)` + + +## 例 +```cpp example +#include +#include + +int ident(int x) { return x; } + +int main() +{ + std::move_only_function f = ident; + + if (f != nullptr) { + std::cout << "not empty" << std::endl; + } + + f = nullptr; + if (f != nullptr) {} + else { + std::cout << "empty" << std::endl; + } +} +``` + +### 出力 +``` +not empty +empty +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) diff --git a/reference/functional/move_only_function/swap.md b/reference/functional/move_only_function/swap.md new file mode 100644 index 0000000000..3bc3956208 --- /dev/null +++ b/reference/functional/move_only_function/swap.md @@ -0,0 +1,72 @@ +# swap +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function template[meta id-type] +* cpp23[meta cpp] + +```cpp +void swap(move_only_function& other) noexcept; +``` + +## 概要 +他の`move_only_function`オブジェクトと中身を入れ替える。 + + +## 効果 +`*this`が持つ関数と`other`が持つ関数を交換する。 + + +## 戻り値 +なし + + +## 例外 +投げない + + +## 例 +```cpp example +#include +#include + +int ident(int x) { return x; } +int add(int x) { return x + 1; } + +int main() +{ + std::move_only_function f = ident; + std::move_only_function g = add; + + // fとgを交換 + f.swap(g); + + std::cout << f(1) << std::endl; // add + std::cout << g(1) << std::endl; // ident +} +``` +* swap[color ff0000] +* f(1)[link op_call.md] +* g(1)[link op_call.md] + +### 出力 +``` +2 +1 +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html) + diff --git a/reference/functional/move_only_function/swap_free.md b/reference/functional/move_only_function/swap_free.md new file mode 100644 index 0000000000..9404837ffd --- /dev/null +++ b/reference/functional/move_only_function/swap_free.md @@ -0,0 +1,67 @@ +# swap (非メンバ関数) +* functional[meta header] +* std[meta namespace] +* move_only_function[meta class] +* function template[meta id-type] +* cpp23[meta cpp] + +```cpp +friend void swap(move_only_function& f1, move_only_function& f2) noexcept; +``` + +## 概要 +2つの`move_only_function`オブジェクトを入れ替える。 + + +## 効果 +`f1.`[`swap`](swap.md)`(f2)` + + +## 戻り値 +なし + + +## 例 +```cpp example +#include +#include + +int ident(int x) { return x; } +int add(int x) { return x + 1; } + +int main() +{ + std::move_only_function f = ident; + std::move_only_function g = add; + + // fとgを交換 + std::swap(f, g); + + std::cout << f(1) << std::endl; // add + std::cout << g(1) << std::endl; // ident +} +``` +* std::swap[color ff0000] +* f(1)[link op_call.md] +* g(1)[link op_call.md] + +### 出力 +``` +2 +1 +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P0288R9 move_only_function](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0288r9.html)