Skip to content

Commit

Permalink
P2548R6 copyable_function (#1199)
Browse files Browse the repository at this point in the history
  • Loading branch information
yohhoy committed Oct 31, 2023
1 parent c9a543d commit 6df7cab
Show file tree
Hide file tree
Showing 13 changed files with 985 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lang/cpp26.md
Expand Up @@ -87,7 +87,7 @@ C++26とは、2026年中に改訂される予定の、C++バージョンの通

### 関数オブジェクト
- 所有権を保持しない[`std::function`](/reference/functional/function.md)として、[`<functional>`](/reference/functional.md)[`std::function_ref`](/reference/functional/function_ref.md.nolink)クラスを追加
- [`std::move_only_function`](/reference/functional/move_only_function.md)のコピー可能版として、[`<functional>`](/reference/functional.md)[`std::copyable_function`](/reference/copyable_function.md.nolink)クラスを追加
- [`std::move_only_function`](/reference/functional/move_only_function.md)のコピー可能版として、[`<functional>`](/reference/functional.md)[`std::copyable_function`](/reference/functional/copyable_function.md)クラスを追加
- [`std::bind_front()`](/reference/functional/bind_front.md)[`std::bind_back()`](/reference/functional/bind_back.md.nolink)に、非型テンプレート引数として関数を指定するオーバーロードを追加
- 関連して、非型テンプレート引数の関数オブジェクトを反転させられるよう、[`not_fn()`](/reference/functional/not_fn.md)に非型テンプレート引数版のオーバーロードを追加

Expand Down
4 changes: 3 additions & 1 deletion reference/functional.md
Expand Up @@ -25,7 +25,9 @@ struct doubler {
|----------------------------------------------------------|----------------------------------------|-------|
| [`function`](functional/function.md) | 関数・関数オブジェクトの多相的なラッパー(class template) | C++11 |
| [`bad_function_call`](functional/bad_function_call.md) | 不正な関数呼び出しに関する例外(class) | C++11 |
| [`move_only_function`](functional/move_only_function.md) | 関数・関数オブジェクトの多相的な軽量ラッパー(class template) | C++23 |
| [`move_only_function`](functional/move_only_function.md) | ムーブのみ可能な関数・関数オブジェクトの多相軽量ラッパー(class template) | C++23 |
| [`copyable_function`](functional/copyable_function.md) | コピー可能な関数・関数オブジェクトの多相軽量ラッパー(class template) | C++26 |
| [`function_ref`](functional/function_ref.md.nolink) | 関数・関数オブジェクトの多相参照ラッパー(class template) | C++26 |
## 統一的な関数呼び出し
Expand Down
243 changes: 243 additions & 0 deletions reference/functional/copyable_function.md
@@ -0,0 +1,243 @@
# copyable_function
* functional[meta header]
* class template[meta id-type]
* std[meta namespace]
* cpp26[meta cpp]

```cpp
namespace std {
template<class... S>
class copyable_function; // 宣言のみ

template<class R, class... ArgTypes>
class copyable_function<R(ArgTypes...) /*cv*/ /*ref*/ noexcept(/*noex*/)>;
}
```
## 概要
`copyable_function`クラステンプレートは、パラメータの型リスト`ArgTypes...`、戻り値の型`R`に合致する、あらゆる関数ポインタ、関数オブジェクト、メンバ関数ポインタ、メンバ変数ポインタを保持できるクラスである。
下記全ての組み合わせ(12種類)に対して、クラステンプレートの部分特殊化が提供される。
- CV修飾子 *cv* : `const`, CV修飾無し
- 参照修飾子 *ref* : `&`, `&&`, 参照修飾無し
- noexcept例外指定 *noex* : `true`, `false`
### `function`との比較
[`std::function`](function.md)と比べて、`std::copyable_function`は下記の特徴をもつ。
- 関数型のCV修飾/参照修飾/noexcept例外指定をサポートする。
- const性などを正しく伝搬することでバグ発生リスクを軽減する
- [`target_type`](function/target_type.md)型と[`target()`](function/target.md)を提供しない。
- 実行時型情報(RTTI)非依存
- [関数呼び出し](copyable_function/op_call.md)は強い事前条件を持つ。
- 関数呼び出し時のnullチェックが要求されない
- クラステンプレート引数の[推論補助](/lang/cpp17/type_deduction_for_class_templates.md)を提供しない。
## メンバ関数
### 構築・破棄
| 名前 | 説明 | 対応バージョン |
|-----------------|----------------|----------------|
| [`(constructor)`](copyable_function/op_constructor.md) | コンストラクタ | C++26 |
| [`(destructor)`](copyable_function/op_destructor.md) | デストラクタ | C++26 |
| [`operator=`](copyable_function/op_assign.md) | 代入演算子 | C++26 |
| [`swap`](copyable_function/swap.md) | 他の`copyable_function`オブジェクトと中身を入れ替える | C++26 |
| [`operator bool`](copyable_function/op_bool.md) | 関数呼び出しが可能か調べる | C++26 |
| [`operator()`](copyable_function/op_call.md) | 関数呼び出し | C++26 |
## メンバ型
| 名前 | 説明 | 対応バージョン |
|-----------------|----------------|----------------|
| `result_type` | 関数の戻り値の型(テンプレートパラメータ`R`) | C++26 |
## 非メンバ関数
| 名前 | 説明 | 対応バージョン |
|-----------------|----------------|----------------|
| [`operator==`](copyable_function/op_equal.md) | 等値比較 | C++26 |
| [`operator!=`](copyable_function/op_not_equal.md) | 非等値比較 | C++26 |
| [`swap`](copyable_function/swap_free.md) | 2つの`copyable_function`オブジェクトを入れ替える | C++26 |
## 例
### 例1: 基本の使い方
```cpp example
#include <functional>
#include <iostream>
int add(int x) { return x + 1; }
int main()
{
// 関数を代入
std::copyable_function<int(int)> f = add;
// 関数オブジェクトを代入
f = [](int x) { return x + 1; };
// 保持している関数を呼び出す
int result = f(1);
std::cout << result << std::endl;
}
```
* std::copyable_function[color ff0000]
* f(1)[link copyable_function/op_call.md]

#### 出力
```
2
```

### 例2: const性の伝搬
```cpp
#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 << "-- copyable_function" << std::endl;
std::copyable_function<std::string(void)> mof1 = Functor{};
const std::copyable_function<std::string(void)> mof2 = Functor{}; // (呼び出し時に不適格)
std::copyable_function<std::string(void) const> mof3 = Functor{};
const std::copyable_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;
}
```
* std::copyable_function[color ff0000]
* std::function[link function.md]
#### 出力
```
-- copyable_function
mof1: non-const
mof3: const
mof4: const
-- function
fn1: non-const
fn2: non-const
```
### 例3: 左辺値/右辺値の伝搬
```cpp example
#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 << "-- copyable_function" << std::endl;
std::copyable_function<std::string(void)> mof1 = Functor{};
std::copyable_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;
}
```
* std::copyable_function[color ff0000]
* std::function[link function.md]

#### 出力
```
-- copyable_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指定の伝搬
```cpp example
#include <functional>

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

int main()
{
std::copyable_function<void(void)> mof1 = func;
std::copyable_function<void(void)> mof2 = func_noex;
//std::copyable_function<void(void) noexcept> mof3 = func; // 不適格
std::copyable_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()));
}
```
* std::copyable_function[color ff0000]
* std::function[link function.md]

#### 出力
```
```


## バージョン
### 言語
- C++26

### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??


## 関連項目
- [`function`](function.md)
- [`move_only_function`](move_only_function.md)


## 参照
- [P2548R6 copyable_function](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2548r6.pdf)
73 changes: 73 additions & 0 deletions reference/functional/copyable_function/op_assign.md
@@ -0,0 +1,73 @@
# operator=
* functional[meta header]
* std[meta namespace]
* copyable_function[meta class]
* function[meta id-type]
* cpp26[meta cpp]

```cpp
copyable_function& operator=(const copyable_function& f); // (1)

copyable_function& operator=(copyable_function&& f); // (2)

copyable_function& operator=(nullptr_t); noexcept; // (3)

template<class F>
copyable_function& operator=(F&& f); // (4)
```

## 効果

- (1) : コピー代入。[`copyable_function`](op_constructor.md)`(f).`[`swap`](swap.md)`(*this)`
- (2) : ムーブ代入。[`copyable_function`](op_constructor.md)`(`[`std::move`](/reference/utility/move.md)`(f)).`[`swap`](swap.md)`(*this)`
- (3) : `*this`が有効な関数ポインタ、メンバポインタ、もしくは関数オブジェクトを持っている場合、それを解放する。
- (4) : [`copyable_function`](op_constructor.md)`(`[`std::forward`](/reference/utility/forward.md)`<F>(f)).`[`swap`](swap.md)`(*this)`


## 戻り値
`*this`


## 例外
- (3) : 投げない


##
```cpp example
#include <iostream>
#include <functional>

int ident(int x) { return x; }

int main()
{
std::copyable_function<int(int)> f;

// 関数を代入
f = ident;

int result = f(1);
std::cout << result << std::endl;
}
```
* f(1)[link op_call.md]
### 出力
```
1
```
## バージョン
### 言語
- C++26
### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??
## 参照
- [P2548R6 copyable_function](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2548r6.pdf)
58 changes: 58 additions & 0 deletions reference/functional/copyable_function/op_bool.md
@@ -0,0 +1,58 @@
# operator bool
* functional[meta header]
* std[meta namespace]
* copyable_function[meta class]
* function[meta id-type]
* cpp26[meta cpp]

```cpp
explicit operator bool() const noexcept;
```

## 概要
関数呼び出しが可能か調べる。


## 戻り値
呼び出す関数を持っていれば`true`、そうでなければ`false`を返す。


##
```cpp example
#include <iostream>
#include <functional>

int ident(int x) { return x; }

int main()
{
std::copyable_function<int(int)> f = ident;

if (f) {
std::cout << "not empty" << std::endl;
}
else {
std::cout << "empty" << std::endl;
}
}
```
### 出力
```
not empty
```
## バージョン
### 言語
- C++26
### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??
## 参照
- [P2548R6 copyable_function](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2548r6.pdf)

0 comments on commit 6df7cab

Please sign in to comment.