Skip to content

Commit fa239b6

Browse files
committed
C++26対応としてapplyの戻り値型を取得するメタ関数を追加 #1522
1 parent 038e14b commit fa239b6

6 files changed

Lines changed: 281 additions & 4 deletions

File tree

lang/cpp26.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,9 @@ C++26とは、2026年中に改訂される予定の、C++バージョンの通
464464
- [`begin()`](/reference/optional/optional/begin.md)メンバ関数
465465
- [`end()`](/reference/optional/optional/end.md)メンバ関数
466466
- [`std::optional`](/reference/optional/optional.md)に、参照を保持するための`T&`の部分特殊化を追加
467-
- [`std::apply`](/reference/tuple/apply.md)の戻り値型推論をやめて、戻り値型用の[`std::apply_result`](/reference/tuple/apply_result.md.nolink)クラスを追加し、関連する以下の機能を追加
468-
- [`std::is_applicable`](/reference/type_traits/is_applicable.md.nolink)型特性
469-
- [`std::is_nothrow_applicable`](/reference/type_traits/is_nothrow_applicable.md.nolink)型特性
467+
- [`std::apply`](/reference/tuple/apply.md)の戻り値型推論をやめて、戻り値型用の[`std::apply_result`](/reference/type_traits/apply_result.md)クラスを追加し、関連する以下の機能を追加
468+
- [`std::is_applicable`](/reference/type_traits/is_applicable.md)型特性
469+
- [`std::is_nothrow_applicable`](/reference/type_traits/is_nothrow_applicable.md)型特性
470470
- [`std::ignore`](/reference/tuple/ignore.md)をファーストクラス・オブジェクトとして型を詳細に定義
471471
- [`std::bitset`](/reference/bitset/bitset.md)に、[`std::basic_string_view`](/reference/string_view/basic_string_view.md)を受け取るコンストラクタを追加
472472
- [`<ratio>`](/reference/ratio.md)に、新たなSI接頭辞として、以下を追加

reference/tuple/apply.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,18 @@ namespace std {
1313
template<class F, tuple-like Tuple>
1414
constexpr decltype(auto)
1515
apply(F&& f, Tuple&& t) noexcept(see below); // (1) C++23
16+
17+
template<class F, tuple-like Tuple>
18+
constexpr apply_result_t<F, Tuple>
19+
apply(F&& f, Tuple&& t)
20+
noexcept(is_nothrow_applicable_v<F, Tuple>); // (1) C++26
1621
}
1722
```
1823
* tuple-like[link tuple-like.md]
1924
* tuple-like[link tuple-like.md]
25+
* tuple-like[link tuple-like.md]
26+
* apply_result_t[link /reference/type_traits/apply_result.md]
27+
* is_nothrow_applicable_v[link /reference/type_traits/is_nothrow_applicable.md]
2028
2129
## 概要
2230
タプルを展開し、関数の引数に適用してその関数を実行する。
@@ -69,7 +77,8 @@ return apply-impl(std::forward<F>(f), std::forward<Tuple>(t),
6977

7078

7179
## 例外
72-
C++23から : `I`をパラメータパック`0, 1, ..., (`[`tuple_size_v`](tuple_size.md)`<`[`remove_reference_t`](/reference/type_traits/remove_reference.md)`<Tuple>>-1)`としたとき、例外指定の式は次と等価 : `noexcept(`[`invoke`](/reference/functional/invoke.md)`(std::forward<F>(f), get<I>(std::forward<Tuple>(t))...))`
80+
- C++23から : `I`をパラメータパック`0, 1, ..., (`[`tuple_size_v`](tuple_size.md)`<`[`remove_reference_t`](/reference/type_traits/remove_reference.md)`<Tuple>>-1)`としたとき、例外指定の式は次と等価 : `noexcept(`[`invoke`](/reference/functional/invoke.md)`(std::forward<F>(f), get<I>(std::forward<Tuple>(t))...))`
81+
- C++26から : 例外指定は[`is_nothrow_applicable_v`](/reference/type_traits/is_nothrow_applicable.md)`<F, Tuple>`
7382

7483

7584
##
@@ -117,6 +126,9 @@ hello
117126
- [`std::tuple`](../tuple.md)
118127
- [INVOKE](/reference/concepts/Invoke.md)
119128
- [`tuple-like`](tuple-like.md)
129+
- [`apply_result`](/reference/type_traits/apply_result.md)
130+
- [`is_applicable`](/reference/type_traits/is_applicable.md)
131+
- [`is_nothrow_applicable`](/reference/type_traits/is_nothrow_applicable.md)
120132
121133
122134
## 参照
@@ -130,3 +142,5 @@ hello
130142
- C++20から効果説明の`decay_t`を`remove_cvref_t`へ変更。
131143
- [P2517R1 Add a conditional `noexcept` specification to `std::apply`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2517r1.html)
132144
- C++23から条件付きで`noexcept`例外指定が行われる。
145+
- [P1317R2 Remove return type deduction in `std::apply`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1317r2.pdf)
146+
- C++26から戻り値型が`decltype(auto)`から`apply_result_t<F, Tuple>`に変更され、SFINAEフレンドリーになった。

reference/type_traits.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@
182182
| [`is_invocable_r`](type_traits/is_invocable_r.md) | 関数呼び出し可能でその戻り値型がある型へ変換可能かを調べる (class template) | C++17 |
183183
| [`is_nothrow_invocable`](type_traits/is_nothrow_invocable.md) | 例外を投げずに関数呼び出し可能かを調べる (class template) | C++17 |
184184
| [`is_nothrow_invocable_r`](type_traits/is_nothrow_invocable_r.md) | 例外を投げずに関数呼び出し可能でその戻り値型がある型へ変換可能かを調べる (class template) | C++17 |
185+
| [`is_applicable`](type_traits/is_applicable.md) | タプルを展開して関数呼び出し可能かを調べる (class template) | C++26 |
186+
| [`is_nothrow_applicable`](type_traits/is_nothrow_applicable.md) | 例外を投げずにタプルを展開して関数呼び出し可能かを調べる (class template) | C++26 |
185187

186188

187189
## その他の変換
@@ -202,6 +204,7 @@
202204
| [`underlying_type`](type_traits/underlying_type.md) | 列挙型の基底型を取得する (class template) | C++11 |
203205
| [`result_of`](type_traits/result_of.md) | 関数の戻り値の型を取得する (class template) | C++11 |
204206
| [`invoke_result`](type_traits/invoke_result.md) | 関数の戻り値の型を取得する (class template) | C++17 |
207+
| [`apply_result`](type_traits/apply_result.md) | タプルを展開して関数を呼び出した場合の戻り値の型を取得する (class template) | C++26 |
205208
| [`unwrap_reference`](type_traits/unwrap_reference.md) | [`reference_wrapper<T>`](/reference/functional/reference_wrapper.md)型を`T&`型に展開する (class template) | C++20 |
206209
| [`unwrap_ref_decay`](type_traits/unwrap_ref_decay.md) | [`reference_wrapper<T>`](/reference/functional/reference_wrapper.md)型を`T&`型に展開し、型推論規則による型変換を行う (class template) | C++20 |
207210

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# apply_result
2+
* type_traits[meta header]
3+
* std[meta namespace]
4+
* class template[meta id-type]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
namespace std {
9+
template <class F, class Tuple>
10+
struct apply_result;
11+
12+
template <class F, class Tuple>
13+
using apply_result_t = typename apply_result<F, Tuple>::type;
14+
}
15+
```
16+
17+
## 概要
18+
関数呼び出し可能な型`F`に対して、[`tuple-like`](/reference/tuple/tuple-like.md)な型`Tuple`の要素を展開して[`apply`](/reference/tuple/apply.md)した場合の戻り値型を取得する。
19+
20+
[`invoke_result`](invoke_result.md)の[`apply`](/reference/tuple/apply.md)版であり、タプルの要素を引数として関数を呼び出した結果の型を求める。
21+
22+
23+
## 要件
24+
型`F`および`Tuple`が、完全型であること。もしくは`const`/`volatile`修飾された(あるいはされていない)`void`か、要素数不明の配列型であること。
25+
26+
27+
## 効果
28+
`ELEMS-OF(T)`を、`make_index_sequence<tuple_size_v<remove_reference_t<T>>>`が示す`index_sequence`の特殊化のテンプレート引数である`size_t`のパラメータパック`N`に対する、パラメータパック`get<N>(declval<T>())`とする。
29+
30+
式[*INVOKE*](/reference/concepts/Invoke.md)`(declval<F>(), ELEMS-OF(Tuple)...)`が未評価オペランドとして扱われたときに適格であるならば、メンバ型`type`は`decltype(`[*INVOKE*](/reference/concepts/Invoke.md)`(declval<F>(), ELEMS-OF(Tuple)...))`を示す。そうでなければ、メンバ型`type`は定義されない。
31+
32+
アクセスチェックは`F`および`Tuple`と無関係なコンテキストで行われる。式の直接のコンテキストの妥当性のみが考慮される。
33+
34+
35+
## 備考
36+
このメタ関数はC++26で追加された。C++23まで[`apply`](/reference/tuple/apply.md)の戻り値型は`decltype(auto)`による型推論が使われていたが、これはSFINAEフレンドリーではなかった。`apply_result`を使うことで、[`apply`](/reference/tuple/apply.md)の呼び出し可能性をコンセプトやSFINAEで判定できるようになった。
37+
38+
39+
## 例
40+
```cpp example
41+
#include <tuple>
42+
#include <type_traits>
43+
#include <string>
44+
45+
int add(int a, int b) { return a + b; }
46+
47+
int main()
48+
{
49+
using args_t = std::tuple<int, int>;
50+
51+
// apply(add, tuple<int, int>) の戻り値型は int
52+
static_assert(std::is_same_v<
53+
std::apply_result_t<decltype(&add), args_t>,
54+
int
55+
>);
56+
57+
// 呼び出し不可能な場合、apply_result にはメンバ型 type がない
58+
// (SFINAEフレンドリー)
59+
static_assert(!requires {
60+
typename std::apply_result_t<decltype(&add), std::tuple<std::string>>;
61+
});
62+
}
63+
```
64+
* std::apply_result_t[color ff0000]
65+
66+
### 出力
67+
```
68+
```
69+
70+
## バージョン
71+
### 言語
72+
- C++26
73+
74+
### 処理系
75+
- [Clang](/implementation.md#clang): 22 [mark noimpl]
76+
- [GCC](/implementation.md#gcc): 15 [mark noimpl]
77+
- [Visual C++](/implementation.md#visual_cpp): 2026 Update 2 [mark noimpl]
78+
79+
80+
## 関連項目
81+
- [`invoke_result`](invoke_result.md)
82+
- [`is_applicable`](is_applicable.md)
83+
- [`is_nothrow_applicable`](is_nothrow_applicable.md)
84+
- [`apply`](/reference/tuple/apply.md)
85+
86+
87+
## 参照
88+
- [P1317R2 Remove return type deduction in `std::apply`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1317r2.pdf)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# is_applicable
2+
* type_traits[meta header]
3+
* std[meta namespace]
4+
* class template[meta id-type]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
namespace std {
9+
template <class F, class Tuple>
10+
struct is_applicable;
11+
12+
template <class F, class Tuple>
13+
inline constexpr bool is_applicable_v = std::is_applicable<F, Tuple>::value;
14+
}
15+
```
16+
17+
## 概要
18+
関数呼び出し可能な型`F`に対して、[`tuple-like`](/reference/tuple/tuple-like.md)な型`Tuple`の要素を展開して[`apply`](/reference/tuple/apply.md)による呼び出しが可能かどうかを調べる。
19+
20+
[`is_invocable`](is_invocable.md)の[`apply`](/reference/tuple/apply.md)版である。
21+
22+
23+
## 要件
24+
型`F`および`Tuple`が、完全型であること。もしくは`const`/`volatile`修飾された(あるいはされていない)`void`か、要素数不明の配列型であること。
25+
26+
27+
## 効果
28+
`ELEMS-OF(T)`を、`make_index_sequence<tuple_size_v<remove_reference_t<T>>>`が示す`index_sequence`の特殊化のテンプレート引数である`size_t`のパラメータパック`N`に対する、パラメータパック`get<N>(declval<T>())`とする。
29+
30+
[`tuple-like`](/reference/tuple/tuple-like.md)`<Tuple>`が`true`であり、かつ式[*INVOKE*](/reference/concepts/Invoke.md)`(declval<F>(), ELEMS-OF(Tuple)...)`が未評価オペランドとして扱われたときに適格であるならば[`true_type`](true_type.md)から派生し、そうでなければ[`false_type`](false_type.md)から派生する。
31+
32+
33+
## 例
34+
```cpp example
35+
#include <tuple>
36+
#include <type_traits>
37+
#include <string>
38+
#include <iostream>
39+
40+
int add(int a, int b) { return a + b; }
41+
void no_args() {}
42+
43+
int main()
44+
{
45+
std::cout << std::boolalpha;
46+
47+
// add(int, int) に tuple<int, int> を展開して呼び出し可能
48+
std::cout << std::is_applicable_v<decltype(&add), std::tuple<int, int>> << std::endl;
49+
50+
// add(int, int) に tuple<int> では引数が足りない
51+
std::cout << std::is_applicable_v<decltype(&add), std::tuple<int>> << std::endl;
52+
53+
// no_args() に空のタプルで呼び出し可能
54+
std::cout << std::is_applicable_v<decltype(&no_args), std::tuple<>> << std::endl;
55+
56+
// no_args() に tuple<int> は引数が多すぎる
57+
std::cout << std::is_applicable_v<decltype(&no_args), std::tuple<int>> << std::endl;
58+
}
59+
```
60+
* std::is_applicable_v[color ff0000]
61+
62+
### 出力
63+
```
64+
true
65+
false
66+
true
67+
false
68+
```
69+
70+
## バージョン
71+
### 言語
72+
- C++26
73+
74+
### 処理系
75+
- [Clang](/implementation.md#clang): 22 [mark noimpl]
76+
- [GCC](/implementation.md#gcc): 15 [mark noimpl]
77+
- [Visual C++](/implementation.md#visual_cpp): 2026 Update 2 [mark noimpl]
78+
79+
80+
## 関連項目
81+
- [`is_invocable`](is_invocable.md)
82+
- [`is_nothrow_applicable`](is_nothrow_applicable.md)
83+
- [`apply_result`](apply_result.md)
84+
- [`apply`](/reference/tuple/apply.md)
85+
86+
87+
## 参照
88+
- [P1317R2 Remove return type deduction in `std::apply`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1317r2.pdf)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# is_nothrow_applicable
2+
* type_traits[meta header]
3+
* std[meta namespace]
4+
* class template[meta id-type]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
namespace std {
9+
template <class F, class Tuple>
10+
struct is_nothrow_applicable;
11+
12+
template <class F, class Tuple>
13+
inline constexpr bool is_nothrow_applicable_v
14+
= std::is_nothrow_applicable<F, Tuple>::value;
15+
}
16+
```
17+
18+
## 概要
19+
関数呼び出し可能な型`F`に対して、[`tuple-like`](/reference/tuple/tuple-like.md)な型`Tuple`の要素を展開して[`apply`](/reference/tuple/apply.md)による呼び出しが可能であり、かつその呼び出しに際して例外を投げないかどうかを調べる。
20+
21+
[`is_nothrow_invocable`](is_nothrow_invocable.md)の[`apply`](/reference/tuple/apply.md)版である。
22+
23+
24+
## 要件
25+
型`F`および`Tuple`が、完全型であること。もしくは`const`/`volatile`修飾された(あるいはされていない)`void`か、要素数不明の配列型であること。
26+
27+
28+
## 効果
29+
`ELEMS-OF(T)`を、`make_index_sequence<tuple_size_v<remove_reference_t<T>>>`が示す`index_sequence`の特殊化のテンプレート引数である`size_t`のパラメータパック`N`に対する、パラメータパック`get<N>(declval<T>())`とする。
30+
31+
[`is_applicable_v`](is_applicable.md)`<F, Tuple>`が`true`であり、かつ式[*INVOKE*](/reference/concepts/Invoke.md)`(declval<F>(), ELEMS-OF(Tuple)...)`がいかなる例外も投げない場合[`true_type`](true_type.md)から派生し、そうでなければ[`false_type`](false_type.md)から派生する。
32+
33+
34+
## 例
35+
```cpp example
36+
#include <tuple>
37+
#include <type_traits>
38+
#include <iostream>
39+
40+
int add(int a, int b) noexcept { return a + b; }
41+
int may_throw(int a, int b) { return a + b; }
42+
43+
int main()
44+
{
45+
std::cout << std::boolalpha;
46+
47+
// add(int, int) noexcept
48+
std::cout << std::is_nothrow_applicable_v<decltype(&add), std::tuple<int, int>> << std::endl;
49+
50+
// may_throw(int, int) は noexcept ではない
51+
std::cout << std::is_nothrow_applicable_v<decltype(&may_throw), std::tuple<int, int>> << std::endl;
52+
53+
// 呼び出し不可能
54+
std::cout << std::is_nothrow_applicable_v<decltype(&add), std::tuple<int>> << std::endl;
55+
}
56+
```
57+
* std::is_nothrow_applicable_v[color ff0000]
58+
59+
### 出力
60+
```
61+
true
62+
false
63+
false
64+
```
65+
66+
## バージョン
67+
### 言語
68+
- C++26
69+
70+
### 処理系
71+
- [Clang](/implementation.md#clang): 22 [mark noimpl]
72+
- [GCC](/implementation.md#gcc): 15 [mark noimpl]
73+
- [Visual C++](/implementation.md#visual_cpp): 2026 Update 2 [mark noimpl]
74+
75+
76+
## 関連項目
77+
- [`is_nothrow_invocable`](is_nothrow_invocable.md)
78+
- [`is_applicable`](is_applicable.md)
79+
- [`apply_result`](apply_result.md)
80+
- [`apply`](/reference/tuple/apply.md)
81+
82+
83+
## 参照
84+
- [P1317R2 Remove return type deduction in `std::apply`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1317r2.pdf)

0 commit comments

Comments
 (0)