Menu

C++ の auto キーワード: 型推論を例で解説

auto キーワードがコンパイラに変数の型を推論させるしくみ — 何を取り除くのか、どこで真価を発揮するのか、そして初心者がはまる落とし穴。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

型はコンパイラに選ばせる

前のページでは、すべての C++ 変数が固定された型 — intdoublestd::string など — を持つことを見ました。その型を手で書き出すのは int count = 0; なら問題ありませんが、型が長くなると煩雑になります。auto キーワード(C++11 以降)は、代入する値からコンパイラに型を 推論 させるので、値を一度書けばあとはコンパイラが埋めてくれます。

重要な考え方: auto は動的型付けでは ありません。各変数は依然として、コンパイル時に確定する 1 つの具体的な型を持ちます。auto はそれを書き出す手間を省くだけです。

auto が価値を発揮する理由

短くて自明な型なら、auto count = 0;int count = 0; は同じくらい読みやすいです。auto が本当に効いてくるのは、長くて反復的な型名 — 標準ライブラリのコンテナやイテレータから生じるような型 — に対してです。

冗長な書き方と auto を使った書き方を比べてみましょう。

// auto なし - 実質的に型を 2 回書いている
std::vector<std::pair<std::string, int>>::iterator it = scores.begin();

// auto あり - コンパイラはすでに型を知っている
auto it = scores.begin();

どちらもまったく同じイテレータ型を宣言します。2 つ目のほうが読みやすく、後で scores を別のコンテナに変えても食い違いが起きません。

完全なプログラムの中で見てみましょう。

範囲ベース for ループでの auto

auto に最もよく出会う場所は、範囲ベースの for ループです。要素の型を手で書き出したいことはほとんどなく、auto をどう書くかでコピーになるか参照になるかが決まります。

目にする 3 つのパターンと、それぞれの意味:

  • for (auto x : v) - x は各要素の コピー です。int には安価ですが、大きなオブジェクトには無駄が多いです。
  • for (auto& x : v) - x参照 です。要素をその場で変更できます。
  • for (const auto& x : v) - x は読み取り専用の参照です。読むだけのときに使います。

次のプログラムは auto& を通してコンテナを変更します。

落とし穴: そのループで for (auto n : nums)(& なし)と書くと、n *= 10 はコピーだけを黙って変更し、nums には手をつけません。コンパイラは警告してくれません。ループは何も役立つことをしないだけです。

auto が取り除くもの

素の auto は、値渡しの関数引数とまったく同じやり方で型を推論します。つまり、最上位の const、参照、volatile を取り除きます。これは、特に指定しない限り auto は常に新しい変更可能なコピーを返すということです。

const を保持したい、あるいはコピーを避けたいなら、修飾子を自分で付け足します。コツは、どんな型でも飾るのと同じように auto を飾ることです。

つまり auto基底 の型を推論し、&const* はその上に付け足すつまみです。auto が型そのもので、const auto& はそれへの読み取り専用の参照です。

よくある間違いと落とし穴

auto は入力の手間を省いてくれますが、型を理解する必要までは省きません。初心者がはまる罠がいくつかあります。

初期化は必須です。 auto は空の宣言からは何も推論できないので、これは紛れもないコンパイルエラーになります。

auto x;        // error: declaration of 'auto x' has no initializer
auto y = 0;    // OK

整数リテラルは int であって double ではありません。 auto half = 1 / 2;int を推論して 0 を格納します。なぜなら 1 / 2 は、auto がそれを見る 前に 整数除算だからです。型は値に従います。

auto は参照を取り除く — ダングリングコピーの不意打ちに注意。 関数が参照を返すのに素の auto で受け取ると、コピーになります。これはホットなループでは本物のパフォーマンスバグになることがあります(反復ごとに大きなオブジェクトのディープコピー)。「見るだけで持ち帰らない」と言いたいときは const auto& を使いましょう。

重要なときに型を隠さない。 auto result = compute(); は、compute の戻り値の型が文脈から自明なら問題ありません。しかし、読み手が result の正体を探し回らなければならないなら、型を書き出すほうが親切な選択になることがあります。auto はノイズを減らすためのものであって、意図を隠すためのものではありません。

次へ: 定数と const

ここまでで、auto は保持を頼まない限り意図的に const を取り除くことを見てきました。すると当然の疑問が湧きます。const は実際に何を保証するのか、そしてそもそもどんなときに値を変更不可と印付けすべきなのか? 次のページでは const、定数式、そして「とりあえずデフォルトで const にする」が C++ で最も役立つ習慣の 1 つである理由を掘り下げます。

よくある質問

C++ で auto キーワードは何をしますか?

auto はコンパイラに、変数の型をその初期化子から推論するよう指示します。auto x = 5;xint にし、auto y = 3.14;ydouble にします。型はコンパイル時に固定されます。auto は動的型付けではなく、自分で型を書く代わりの省略形です。

C++ で auto は const と参照を保持しますか?

いいえ。素の auto は最上位の const、参照、volatile を取り除きます。元が const int& r の場合、auto x = r; は素の int のコピーになります。これらを保持したいなら明示的に書きます。コピーせずに読み取り専用の参照を束縛するには const auto& を使います。

auto で変数を初期化せずに宣言できますか?

いいえ。auto x; はコンパイルエラーになります。コンパイラが型を推論する元となる初期化子がないからです。すべての auto 変数は、宣言した時点で値を与えなければなりません。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める