はじめに
C++で、std::vector<std::string>::iterator
のように、非常に長くて複雑な型名を手で書くのは、面倒で、typoの原因にもなります。
C++11では、このような問題を解決し、コードをより簡潔で読みやすくするために、型の自動推論の仕組みが導入されました。
auto
: 変数を初期化する値から、その変数の型を自動で推論する。decltype
: 式の型を、コンパイル時に取得する。
この記事では、これら2つのキーワードの基本的な使い方と、それによってC++のコードがどのように改善されるかを解説します。
【前提】C++11とは?
C++11は、2011年に正式化されたC++言語のメジャーアップデート版です。auto
による型推論やdecltype
はこのC++11で導入されたため、利用するにはC++11以降に対応したコンパイラが必要です。
1. auto
: 初期化子からの型推論
auto
キーワードを変数の型の代わりに使うと、コンパイラはその変数を初期化している値の型を見て、自動的に変数の型を決定してくれます。
サンプルコード
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
// 1. 基本的な使い方
auto integer_val = 100; // 100はintなので、integer_valはint型になる
auto double_val = 3.14; // 3.14はdoubleなので、double_valはdouble型になる
auto text = "Hello"; // "Hello"はconst char*なので、textはconst char*型になる
// 2. 複雑な型名を簡略化
vector<string> names = {"佐藤", "鈴木"};
// 本来: vector<string>::iterator it = names.begin();
auto it = names.begin(); // itは vector<string>::iterator 型に推論される
// 3. 範囲for文での利用
// for (const string& name : names) と書くのと同じ
for (const auto& name : names) {
cout << name << endl;
}
return 0;
}
解説: auto
を使うことで、特にイテレータのような長い型名を記述する手間が省け、コードが非常にすっきりと読みやすくなります。
2. decltype
: 式からの型取得
decltype
(declared type) は、式を引数に取り、その式が返す値の型をコンパイル時に取得します。auto
が変数を初期化する必要があるのに対し、decltype
は変数の宣言にのみ型を利用できます。
サンプルコード
#include <iostream>
using namespace std;
int main() {
int x = 10;
const double y = 3.14;
// 1. 変数から型を取得
// xの型(int)を持つ変数を宣言
decltype(x) x2;
// 2. 式から型を取得
// x + y の結果の型(double)を持つ変数を宣言
decltype(x + y) z;
cout << "typeid(x2).name(): " << typeid(x2).name() << endl;
cout << "typeid(z).name(): " << typeid(z).name() << endl;
return 0;
}
解説: decltype
は、const
や&
(参照)といった修飾子も含めて、式の型を忠実に再現します。
後置戻り値型 (Trailing Return Type)
C++11では、decltype
とauto
を組み合わせて、関数の戻り値の型を、引数を使った式から決定することができます。
template <typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {
return a + b;
}
解説: -> decltype(a + b)
の部分が、add
関数の戻り値の型が、a + b
という式の型と同じであることを示しています。
まとめ
今回は、C++11で導入された、型の自動推論を行うauto
とdecltype
について解説しました。
auto
: 変数の初期化子から型を推論する。コードを簡潔にする。decltype
: 式から型を取得する。ジェネリックプログラミングなどで、複雑な型を扱う際に強力。
これらの機能を適切に使いこなすことで、冗長な型名の記述を減らし、より読みやすく、メンテナンス性の高い現代的なC++コードを書くことができます。