名前空間
変種
操作

auto 指定子 (C++11以上)

提供: cppreference.com
< cpp‎ | language
 
 
 
 

変数の場合は、その宣言している変数の型がその初期化子から自動的に推定されることを指定します。 関数の場合は、その戻り値の型が後置戻り値型であるか、 return 文から推定される (C++14以上)ことを指定します。 非型テンプレート引数の場合は、その型が実引数から推定されることを指定します。 (C++17以上)

目次

[編集] 構文

auto variable initializer (1) (C++11以上)
auto function -> return type (2) (C++11以上)
auto function (3) (C++14以上)
decltype(auto) variable initializer (4) (C++14以上)
decltype(auto) function (5) (C++14以上)
auto :: (6) (concepts TS)
cv(オプション) auto ref(オプション) parameter (7) (C++14以上)
template < auto Parameter > (8) (C++17以上)
cv(オプション) auto ref(オプション) [ identifier-list ] initializer ; (9) (C++17以上)

[編集] 説明

1) ブロックスコープ、名前空間スコープ、 for ループの初期化文などにおいて変数を宣言するとき、キーワード auto を型指定子として使用することができます。
初期化子の型が決定されると、コンパイラは、関数呼び出しにおけるテンプレートの実引数推定のためのルール (詳細はテンプレートの実引数推定を参照してください) を用いて、キーワード auto を置き換える型を決定します。 キーワード auto には const& などの修飾子が付いていても良く、これらは型の推定に寄与します。 例えば const auto& i = expr; の場合、 i の型は、もし関数呼び出し f(expr) がコンパイルされたならばテンプレート template<class U> void f(const U& u) の引数 u が持ったであろう、ちょうどその型になります。 そのため、 auto&& は、その初期化子に応じて、左辺値参照または右辺値参照のいずれにも推定される可能性があります。 これは範囲 for ループで使用されます。
auto が複数の変数を宣言するために使用された場合は、推定された型は一致しなければなりません。 例えば、宣言 auto i = 0, d = 0.0; は ill-formed ですが、宣言 auto i = 0, *p = &i; は well-formed であり、 autoint として推定されます。
2) 後置戻り値型の構文を使用する関数宣言では、キーワード auto は自動型推定を行いません。 これは構文の一部として供されるだけです。
3) 後置戻り値型の構文を使用しない関数宣言では、キーワード auto は戻り値の型がテンプレートの実引数推定のためのルールを用いて推定されることを指定します。
4) 変数の宣言された型が decltype(auto) の場合は、キーワード auto はその初期化子の式 (または式リスト) で置き換えられ、その実際の型は decltype のためのルールを用いて推定されます。
5) 関数の戻り値の型が decltype(auto) 宣言される場合は、キーワード auto はその return 文の被演算子で置き換えられ、その実際の型は decltype のためのルールを用いて推定されます。
6) auto:: 形式の nested-name-specifier は、制約された型のプレースホルダ推定のためのルールに従ってクラスまたは列挙型に置き換えられるプレースホルダです。
7) ラムダ式における引数の宣言。 (C++14以上) 関数の引数の宣言。 (C++20以上)
8) テンプレートの仮引数auto 宣言された場合、その型は対応する実引数から推定されます。

[編集] ノート

C++11 まで、 auto記憶域期間指定子の意味論を持っていました。

ひとつの宣言の中で auto f() -> int, i = 0; のように 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 << "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