プレースホルダ型指定子 (C++11以上)
変数の場合は、その宣言している変数の型がその初期化子から自動的に推定されることを指定します。
関数の場合は、戻り値の型がその return 文から推定されることを指定します。 |
(C++14以上) |
非型テンプレート引数の場合は、その型が引数から推定されることを指定します。 |
(C++17以上) |
目次 |
[編集] 構文
auto | (1) | (C++11以上) | |||||||
decltype(auto) | (2) | (C++14以上) | |||||||
type-constraint auto | (3) | (C++20以上) | |||||||
type-constraint decltype(auto) | (4) | (C++20以上) | |||||||
type-constraint | - | コンセプト名。 修飾付きでも構いません。 <> で囲まれたテンプレート引数リストを後に付けても構いません。 |
プレースホルダ auto には const や & などの修飾子を付けても構いません。 これらは型の推定に寄与します。 プレースホルダ decltype(auto) は推定される型の唯一の構成要素でなければなりません。 (C++14以上)
[編集] 説明
プレースホルダ型指定子は以下の文脈に現れることができます。
- 変数の型指定子において (例: auto x = expr;)。 型は初期化子から推定されます。
プレースホルダ型指定子がauto
または type-constraintauto
(C++20以上) の場合、変数の型は、関数呼び出しにおけるテンプレートの実引数推定のためのルールを用いて、初期化子から推定されます (詳細についてはテンプレートの実引数推定を参照してください)。
例えば、 const auto& i = expr; が与えられた場合、i
の型は、もし関数呼び出し f(expr) がコンパイルされた場合の架空のテンプレート template<class U> void f(const U& u) における引数u
の型です。 そのため、 auto&& は初期化子によって左辺値参照または右辺値参照のいずれかに推定されることがあります。 これは範囲ベースの for ループで使用されます。
プレースホルダ型指定子が
decltype(auto)
または type-constraintdecltype(auto)
(C++20以上) の場合、推定された型はdecltype(e)
です。 ただしe
は初期化子です。(C++14以上) プレースホルダ型指定子が複数の変数を宣言するために使用された場合、推定された型は一致しなければなりません。 例えば、宣言 auto i = 0, d = 0.0; は ill-formed ですが、宣言 auto i = 0, *p = &i; は well-formed です (
auto
は int として推定されます)。 - new 式の型識別子として。 型は初期化子から推定されます。
new T init
(ただし、 T がプレースホルダ型を含み、 init が括弧で囲まれた初期化子または波括弧で囲まれた初期化子リスト) の場合、 T の型は、架空の宣言 T x init; の変数 x の場合と同様に推定されます。 - (C++14以上) 関数またはラムダ式の戻り値の型において (例: auto& f();)。 戻り値の型はその破棄されない (C++17以上) return 文の被演算子から推定されます。
戻り値の型の推定を参照してください。 - (C++17以上) 非型テンプレート引数の引数宣言において (例: template<auto I> struct A;)。 その型は対応する実引数から推定されます。
さらに、
|
(C++14以上) |
type-constraint が存在する場合、
|
(C++20以上) |
[編集] ノート
C++11 まで、 auto は記憶域期間指定子の意味論を持っていました。
ひとつの宣言の中で auto f() -> int, i = 0; のように auto
の変数と関数を混ぜることは許されていません。
auto 指定子は後置戻り値型が後続する関数宣言子で使用されることもあります。 この場合、宣言された戻り値の型はその後置戻り値型です (それが再びプレースホルダ型であっても構いません)。
auto (*p)() -> int; // int を返す関数へのポインタとして p を宣言します。 auto (*q)() -> auto = p; // p の型から推定した型を返す関数へのポインタとして // q を宣言します。
auto 指定子は構造化束縛宣言で使用されることもあります。 |
(C++17以上) |
auto キーワードは nested-name-specifier で使用されることもあります。 auto:: 形式の nested-name-specifier は制約された型のプレースホルダ推定のためのルールに従ってクラスまたは列挙型によって置き換えられるプレースホルダです。 |
(concepts TS) |
[編集] 例
#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 << "a, before modification through c2 = " << a << '\n'; ++c2; std::cout << "a, after modification through c2 = " << 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}; // C++17 以降はエラー、それまでは std::initializer_list<int> でした。 auto m{5}; // OK、 m は C++17 以降は 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++ ではエラー。 }
出力例:
a, before modification through c2 = 3 a, after modification through c2 = 4