プレースホルダー型指定子 (C++11以降)
プレースホルダー型指定子は、後で、通常は初期化子からの推論によって置き換えられる*プレースホルダー型*を指定します。
目次 |
[編集] 構文
型制約 (オプション) auto |
(1) | ||||||||
型制約 (オプション) decltype(auto) |
(2) | (C++14以降) | |||||||
| type-constraint | - | (C++20以降) コンセプト名、オプションで修飾子付き、オプションで<>で囲まれたテンプレート引数リストが続く |
プレースホルダーautoは、constや&のような修飾子を伴うことができ、それらは型推論に参加します。プレースホルダーdecltype(auto)は、宣言された型の唯一の構成要素でなければなりません。(C++14以降)
|
型制約が存在する場合、プレースホルダーに推論された型を
制約式が無効であるか、falseを返す場合、推論は失敗します。 |
(C++20以降) |
[編集] 解説
プレースホルダー型指定子は、次のコンテキストで現れることがあります。
パラメータ宣言以下のパラメータ宣言において、宣言されたパラメータの型は構文(1)の型である場合があります。
|
(C++14以降) |
|
(C++17以降) |
|
(C++20以降) |
[編集] 関数宣言
プレースホルダー型は、末尾戻り値型を含む関数宣言子の宣言指定子に出現することができます。
|
プレースホルダー型は、関数宣言子の宣言された戻り値型の宣言指定子または型指定子に出現することができます。この場合、戻り値型推論が適用されます。 |
(C++14以降) |
auto f() -> int; // OK: f returns int auto g() { return 0.0; } // OK since C++14: g returns double auto h(); // OK since C++14: h’s return type will be deduced when it is defined
[編集] 変数宣言
プレースホルダー型を使用して宣言された変数の型は、その初期化子から推論されます。この使用法は、変数の初期化宣言で許可されています。
プレースホルダー型は、宣言指定子シーケンスの宣言指定子の1つとして、またはそのような宣言指定子を置き換える型を指定する末尾戻り値型の型指定子の1つとしてのみ現れることができます。この場合、宣言は少なくとも1つの変数を宣言する必要があり、各変数には空でない初期化子が必要です。
// “auto”s in declaration specifiers auto x = 5; // OK: x has type int const auto *v = &x, u = 6; // OK: v has type const int*, u has type const int static auto y = 0.0; // OK: y has type double auto f() -> int; auto (*fp)() -> auto = f; // OK: the “auto” in the trailing return type // can be deduced from f
構造化束縛宣言auto指定子は、構造化束縛宣言で使用できます。 |
(C++17以降) |
[編集] new 式
プレースホルダー型は、new式のtype-idの型指定子シーケンスで使用できます。そのようなtype-idでは、プレースホルダー型は、型指定子シーケンスの型指定子の1つとして、またはそのような型指定子を置き換える型を指定する末尾戻り値型として現れる必要があります。
関数形式キャストauto型指定子は、関数形式キャストの型指定子として使用できます。 |
(C++23から) |
[編集] 注記
C++11まで、autoは記憶域期間指定子の意味を持っていました。
上記で明示的に述べられていないコンテキストでプレースホルダー型を使用するプログラムは不適格です。
宣言が複数のエンティティを宣言し、宣言指定子シーケンスがプレースホルダー型を使用する場合、以下の条件のいずれかが満たされるとプログラムは不適格です。
- 宣言されたエンティティの一部が変数ではない。
- プレースホルダー型を置き換える型が、各推論で同じではない。
auto f() -> int, i = 0; // Error: declares a function and a variable with “auto” auto a = 5, b = {1, 2}; // Error: different types for “auto”
|
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; } // the return type is the type of operator+(T, U) // perfect forwarding of a function call must use decltype(auto) // in case the function it calls returns by reference template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); } template<auto n> // C++17 auto parameter declaration auto f() -> std::pair<decltype(n), decltype(n)> // auto can't deduce from brace-init-list { return {n, n}; } int main() { auto a = 1 + 2; // type of a is int auto b = add(1, 1.2); // type of b is double static_assert(std::is_same_v<decltype(a), int>); static_assert(std::is_same_v<decltype(b), double>); auto c0 = a; // type of c0 is int, holding a copy of a decltype(auto) c1 = a; // type of c1 is int, holding a copy of a decltype(auto) c2 = (a); // type of c2 is int&, an alias of 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>(); //structured binding declaration auto d = {1, 2}; // OK: type of d is std::initializer_list<int> auto n = {5}; // OK: type of n is std::initializer_list<int> // auto e{1, 2}; // Error as of DR n3922, std::initializer_list<int> before auto m{5}; // OK: type of m is int as of DR n3922, initializer_list<int> before // decltype(auto) z = { 1, 2 } // Error: {1, 2} is not an expression // auto is commonly used for unnamed types such as the types of lambda expressions auto lambda = [](int x) { return x + 3; }; // auto int x; // valid C++98, error as of C++11 // auto x; // valid C, error in C++ [](...){}(c0, c1, v, w, d, n, m, lambda); // suppresses "unused variable" warnings }
実行結果の例
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指定子を含む宣言は、2つの変数を それぞれ型 Tとstd::initializer_list<T>で定義できた |
禁止された |
| CWG 1852 | C++14 | decltype(auto)のauto指定子もプレースホルダーであった | プレースホルダーではない この場合に |
| CWG 1892 | C++11 | 関数ポインタのtype-idの戻り値型はautoであった | 禁止された |
| CWG 2476 | C++11 | CWG issue 1892の解決により、初期化子からの 関数ポインタ変数の戻り値型の推論が禁止された |
許可 |
[編集] 参照
- C++23標準 (ISO/IEC 14882:2024)
- 9.2.9.6 プレースホルダー型指定子 [dcl.spec.auto]
- C++20 standard (ISO/IEC 14882:2020)
- 9.2.8.5 プレースホルダー型指定子 [dcl.spec.auto]
- C++17 standard (ISO/IEC 14882:2017)
- 10.1.7.4
auto指定子 [dcl.spec.auto]
- 10.1.7.4
- C++14 standard (ISO/IEC 14882:2014)
- 7.1.6.4
auto指定子 [dcl.spec.auto]
- 7.1.6.4
- C++11 standard (ISO/IEC 14882:2011)
- 7.1.6.4
auto指定子 [dcl.spec.auto]
- 7.1.6.4