変数の型推論
最初のautoは、変数の型推論です。C++11において、変数のauto宣言として使用できるようになりました。
基本データ型の型推論[C++11]
基本データ型から始めましょう。例えば、こんな感じです。
auto i = 10; // int型(整数の既定) auto d = 123.45; // double型(浮動小数点数の既定)
型推論を用いた変数宣言の最もシンプルな形でしょう。intやdoubleがautoになっただけです。右辺の初期化子に10や123.45が指定されているので、これは整数型および浮動小数点数型だろうと推論して、int型とdouble型(正確には符号付き32ビット整数型、倍精度浮動小数点数型)として宣言されます。なんでこうなるかというと、これら(intとdouble)を既定で使うのが最も一般的だろうということなんですね。
同様に、他の型の変数も宣言できます。基本データ型で思いつくものをずらっと並べてみました。
auto u = 10u; // unsigned int型(Uでも可) auto l = 20L; // long型(lでも可) auto ll = 200LL; // long long型(llでも可) auto f = 123.45F; // float型(fでも可) auto ld = 123.45L; // long double型(lでも可) auto b = true; // bool型 auto c = 'A'; // char型
要は、右辺の初期化子に指定するリテラルの表記で、型をコントロールするということです。サフィックスにuかUを付ければ符号なし型、lかLを付ければlong型、浮動小数点数に限ってはfかFを指定することで単精度浮動小数点数型に格下げできます。bool型やchar型に至ってはそのままです(ほかに解釈のしようもありませんね)。
こうなると、型推論なんて簡単じゃないかと思いますよね。もちろん、宣言済みの変数や式を初期化子に指定すれば、その型から推論される型が選択されます。
auto i_v = i; // iはintなのでi_vもint型になる auto i_e = i + 10; // i + 10はint型に評価されるのでi_eもint型になる
文字列型の型推論[C++14]
基本データ型は分かった、でもC++のプログラムでは文字列も多用するのだぞ。文字列はどうなるのだ? はい、もちろん文字列リテラルにも型推論は働きます。以下のリストです。
auto sc = "Hello"; // char *型(const char *型)
このとき、scはchar *型(実装によってはconst char *型)に推論されます。Cを長くやってきた方には自然ですね。ところが、C++にはstd::stringという文字列の取り扱いに特化したクラスがあって、今どきの言語には不可欠で便利な文字列処理の機能を提供してくれます。どのように使うか? ということは各自で調べてほしいのですが、このstd::stringに推論してほしいときは、文字列リテラルにサフィックスsを付加します。ただし、残念なことにこの記法はC++14以降でないと使えません。
auto ss = "Hello"s; // std::string型(C++14以降)
ポインタ型と参照型の型推論[C++11]
ポインタ型と参照型も推論できます。上記の文字列リテラルもポインタ型の一つですね。推論は難しくなく、ポインタなら初期化子をポインタにして、参照ではautoの方にアンパサンド「&」を付けるだけです。
auto i_p = &i; // int *型 auto* i_p2 = &i; // int *型 auto& i_r = i; // int&型
参照の「&」がautoに続いているからといって、auto*でポインタ型になるとは思わないでくださいね。autoに「*」が付いただけではダメで、やはり初期化子はポインタにする必要があるのは変わらないようです。
[NOTE]参照型
Cにおける間接参照ではポインタが当たり前でした。難解な言語仕様の象徴のように扱われるポインタですが、C++にはより安全に使える間接参照として「参照」があります。CからよっこいしょとC++に上がった方の中には、参照なんて使ったこともない! ポインタの方が便利!(筆者です)という方もいらっしゃるかもしれません。
参照は、文字通り別の変数への参照です。別名と言ってもいいかもしれません。ポインタが、ポインタ演算子(*)を付けて宣言されるのに対し、参照は参照演算子(&)を付けて宣言します。「&」と言えばアドレス演算子としての使い方を思い出す人も多いでしょうが、参照での「&」は全くの別物です。
int x = 100; // int型変数xを宣言 int& r = x; // xへの参照変数を宣言
参照変数を使って、値の取り出しや書き換えができるのはポインタと変わりませんが、大きな違いがいくつかあります。
- 参照先が未定義という状態は許されない(ヌルポインタのような扱いはできない)
- ポインタ演算のように参照先を変更することはできない
- 値の参照に*演算子は不要
- 構造体やクラスの参照からメンバへのアクセスはアロー演算子(->)ではなくドット演算子(.)を使う