Placeholder type specifiers (since C++11)
プレースホルダー型指定子は、後に置き換えられる プレースホルダー型 を指定します。通常は 初期化子 からの推論によって置き換えられます。
目次 |
構文
type-constraint
(オプション)
auto
|
(1) | ||||||||
type-constraint
(オプション)
decltype(auto)
|
(2) | (C++14以降) | |||||||
| type-constraint | - |
(since C++20)
オプションで修飾された
concept
名、その後にオプションで
<>
で囲まれたテンプレート引数リストが続くもの
|
プレースホルダー
auto
は、
const
や
&
などの修飾子を伴うことができ、これらは型推論に参加します。
プレースホルダー
decltype
(
auto
)
は宣言された型の唯一の構成要素でなければなりません。
(C++14以降)
|
type-constraint
が存在する場合、
制約式が無効であるか、 false を返す場合、推論は失敗します。 |
(C++20以降) |
説明
プレースホルダ型指定子は以下の文脈で現れる可能性があります:
パラメータ宣言以下のパラメータ宣言において、宣言されるパラメータの型は構文 (1) の形式をとることができます:
|
(C++14以降) |
|
(C++17以降) |
|
(C++20以降) |
関数宣言
プレースホルダ型は、 宣言指定子 内で、 関数宣言子 の末尾戻り値型を含むものに現れることができます。
|
プレースホルダ型は、関数宣言子の宣言された戻り値型の宣言指定子または 型指定子 に現れることができます。 この場合、 戻り値型の推論 が適用されます。 |
(C++14以降) |
auto f() -> int; // OK: fはintを返す auto g() { return 0.0; } // C++14以降OK: gはdoubleを返す auto h(); // C++14以降OK: hの戻り値型は定義時に推論される
変数宣言
プレースホルダー型を使用して宣言された変数の型は、その 初期化子 から推論されます。この使用法は変数の初期化宣言で許可されています。
プレースホルダ型は、宣言指定子シーケンス内の declaration specifiers の1つとして、またはそのような宣言指定子を置き換える型を指定する後置戻り値型の型指定子の1つとしてのみ現れます。この場合、宣言は少なくとも1つの変数を宣言しなければならず、各変数は空でない初期化子を持たなければなりません。
// 宣言指定子における「auto」 auto x = 5; // OK: x の型は int const auto *v = &x, u = 6; // OK: v の型は const int*、u の型は const int static auto y = 0.0; // OK: y の型は double auto f() -> int; auto (*fp)() -> auto = f; // OK: 後置戻り値型の「auto」は // f から推論可能
構造化束縛宣言auto 指定子は 構造化束縛 宣言で使用できます。 |
(C++17以降) |
new expressions
プレースホルダ型は、 new式 の型IDの型指定子シーケンスで使用できます。このような型IDでは、プレースホルダ型は型指定子シーケンス内の型指定子の1つとして、またはそのような型指定子を置き換える型を指定する後置戻り値型として現れなければなりません。
関数形式キャストauto 型指定子は、 関数形式キャスト の型指定子として使用できます。 |
(C++23以降) |
注記
C++11まで、 auto は storage duration specifier の意味を持っていました。
上記で明示的に述べられていない文脈でプレースホルダ型を使用するプログラムは不適格です。
宣言が複数のエンティティを宣言し、かつ宣言指定子シーケンスがプレースホルダ型を使用する場合、以下のいずれかの条件が満たされるとプログラムは不適格となります:
- 宣言されているエンティティの一部は変数ではありません。
- プレースホルダー型を置き換える型が各推論で同一ではありません。
auto f() -> int, i = 0; // エラー: 「auto」で関数と変数を宣言している auto a = 5, b = {1, 2}; // エラー: 「auto」の型が異なる
置換されていないプレースホルダー型を持つ関数または変数が式によって参照される場合、プログラムは不適格です。
auto v = 1; auto l = [&] { v++; return l;// エラー: lのプレースホルダ型が置換されていません }; std::function<void()> p = [&] { v++; return p;// OK };
|
auto キーワードは、ネストされた名前指定子でも使用できます。 auto :: の形式のネストされた名前指定子は、プレースホルダーであり、 制約付き型 プレースホルダー推論の規則に従ってクラス型または列挙型に置き換えられます。 |
(concepts TS) |
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_decltype_auto
|
201304L
|
(C++14) | decltype ( auto ) |
キーワード
例
#include <iostream> #include <utility> template<class T, class U> auto add(T t, U u) { return t + u; } // 戻り値の型は operator+(T, U) の型 // 関数呼び出しの完全転送は参照を返す可能性があるため decltype(auto) を使用する必要がある template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); } template<auto n> // C++17 auto パラメータ宣言 auto f() -> std::pair<decltype(n), decltype(n)> // auto は波括弧初期化リストから推論できない { return {n, n}; } int main() { auto a = 1 + 2; // a の型は int auto b = add(1, 1.2); // b の型は double static_assert(std::is_same_v<decltype(a), int>); static_assert(std::is_same_v<decltype(b), double>); auto c0 = a; // c0 の型は int、a のコピーを保持 decltype(auto) c1 = a; // c1 の型は int、a のコピーを保持 decltype(auto) c2 = (a); // c2 の型は int&、a のエイリアス std::cout << "before modification through c2, a = " << a << '\n'; ++c2; std::cout << " after modification through c2, a = " << a << '\n'; auto [v, w] = f<0>(); // 構造化束縛宣言 auto d = {1, 2}; // OK: d の型は std::initializer_list<int> auto n = {5}; // OK: n の型は std::initializer_list<int> // auto e{1, 2}; // DR n3922 以降エラー、以前は std::initializer_list<int> auto m{5}; // OK: DR n3922 以降 m の型は int、以前は initializer_list<int> // decltype(auto) z = { 1, 2 } // エラー: {1, 2} は式ではない // auto はラムダ式の型など無名の型によく使用される auto lambda = [](int x) { return x + 3; }; // auto int x; // C++98 では有効、C++11 以降エラー // auto x; // C では有効、C++ ではエラー [](...){}(c0, c1, v, w, d, n, m, lambda); // 「未使用変数」警告を抑制 }
出力例:
before modification through c2, a = 3 after modification through c2, a = 4
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| CWG 1265 | C++11 |
auto
指定子を使用して、戻り値型を後置する関数の宣言と変数の定義を
1つの宣言文で行うことができた |
禁止 |
| CWG 1346 | C++11 | 括弧付きの式リストを auto 変数に代入できなかった | 許可 |
| CWG 1347 | C++11 |
auto
指定子を使用した宣言で、型がそれぞれ
T
と
std::
initializer_list
<
T
>
の2つの変数を
定義できた |
禁止 |
| CWG 1852 | C++14 | decltype ( auto ) 内の auto 指定子もプレースホルダーであった |
この場合はプレースホルダーではない
|
| CWG 1892 | C++11 | 関数ポインタ型IDの戻り値型を auto とすることができた | 禁止 |
| CWG 2476 | C++11 |
CWG issue 1892
の解決により、関数ポインタ変数の
戻り値型の初期化子からの推論が禁止された |
許可 |
| N3922 | C++11 | auto の直接リスト初期化は std::initializer_list を推論する |
複数要素の場合は不適格、
単一要素の場合は要素型を推論 |
参考文献
- C++23標準 (ISO/IEC 14882:2024):
-
- 9.2.9.6 プレースホルダ型指定子 [dcl.spec.auto]
- C++20 標準 (ISO/IEC 14882:2020):
-
- 9.2.8.5 プレースホルダ型指定子 [dcl.spec.auto]
- C++17規格 (ISO/IEC 14882:2017):
-
-
10.1.7.4
auto指定子 [dcl.spec.auto]
-
10.1.7.4
- C++14 標準 (ISO/IEC 14882:2014):
-
-
7.1.6.4
auto指定子 [dcl.spec.auto]
-
7.1.6.4
- C++11標準 (ISO/IEC 14882:2011):
-
-
7.1.6.4
auto指定子 [dcl.spec.auto]
-
7.1.6.4