【初心者C++er Advent Calendar 2016 17日目】C++ で型と値を理解する

初心者C++er Advent Calendar 2016 17日目の記事です。
初心者ネタに型と値の話でも。

[値とは]

C++ における値とは数値や文字列、クラスのインスタンスなどを指します。

// 数値や小数
42
3.14f

// 文字や文字列
'c'
"homu"

// クラスのインスタンス
std::string{}
std::vector<int>{}

まあ要はデータそのものですね。

[型とは]

一方、C++ における型とは intcharstd::string などを指します。
型は一般的に『何かの値を受け取るものを定義する時』つまり『変数を定義する時』や『関数の引数を定義する時』などに使用します。

// 42 という『値』を受け取る変数を『int 型』として定義する
int n = 42;

// 『int 型』と『float 型』を受け取って『bool 型』を返す関数を宣言する
bool func(int, float);

// 関数に『値』を渡して『値』を受け取る
bool b = func(42, 3.14f);

このように型とは『値と対になるような存在』になりどんな値にも『型』は存在します。

[型による制約]

基本的には『同じ型』の変数に対してのみ値を代入することが出来ます。

int a;      // int 型の変数を定義
a = -10;   // int 型の値を代入する
a = "homu";  // Error: 他の型を代入することは出来ない

このようにすることで任意の変数は『定義した時の型』である事が保証されます。
ただし、値によっては『別の型』を代入する事ができる場合もあります。

float b;    // float 型の変数を定義
b = 3.14f; // float 型の値を代入する
b = 42;        // OK: int 型の値を代入してもエラーにならない

このように他の型へ変換されることを暗黙の型変換と呼びます。
C++ ではしばしばこのように暗黙的に別の型へと変換される事があるので注意してください。
このように C++ では『値』がどんな『型』になるのか、また『値を演算した結果(関数を呼び出した結果)』どんな『型に変換されるのか』を意識して書くことが重要になってきます。
これに慣れてくると

result = 42 + 3.14f;

というような処理が

float = int + float;

のように型に脳内変換されます。

[値から型を定義する]

さて、ちょっと型の話をしていきましょう。
コードを書いてると値や式から型を取得したいと思うことが度々あります。

int a = 10;
float b = 3.14f;
// どんな型を返すんだっけ???
??? c = a + b;

そういう時は C++11 から追加された decltype() という機能を使用します。
decltype() は式(値)を渡すことで『その式(値)の型』を返します。

int a = 42;
decltype(a);          // int 型を返す
decltype(a) b = 10;   // 型の変わりに使用することができる

// typedef などで使用することもできる
typedef decltype(a) a_type;

float f = 3.14f;
decltype(a + f) result = a + f;   // decltype() には式も渡せる

decltype(func(a, b)) result2 = func(a, b);   // 関数も渡すことができる

int const n = 42;

// const 修飾子も加味した型を返す
decltype(n);      // const int

こんな感じです。
基本的に『decltype() を定義したスコープから見える変数』はすべて参照する事が出来ます。
ですので以下のようにC++11 で追加された『後置戻り値型』でも decltype() が使用できます。

template<typename T, typename U>
auto
plus(T a, U b)
// 型情報だけでは演算結果の型を取得するのは難しいが
// decltype() を利用すれば式から型を推論することができる
->decltype(a + b){
    return a + b;
}

decltype() が具体的にどのような型を返すのかは以下のサイトがわかりやすく解説しています。

本の虫: decltypeの訓練

[まとめ]

そんな感じで値と型の話について書いてみました。
C++(に限らないけど)において『型情報』というのは重要なファクターになります。
特に昨今のテンプレートや auto などを使用したコードでは『表面の型』が見えないことが多いです。
そういう時こそ『型』を意識してコードを書いていくことが C++ を学ぶ上で大切になっていきます。
動的型付け言語を普段書いている人にとって『型情報』というのはめんどくさい要因の一つだと思います。
しかし、『型による制約』によるリターンもとても大きいものではあります。
C++ 初心者の人はコードを書いてる時に少しだけ型について意識して書いてみると C++ への理解がより深まると思います。