C++ メモ：変数

# 前書き
主に自分用。まァ役に立てればなによりですが。

# 内容
## 参照
### 参照とポインタ
参照はオブジェクトではないので、参照へのポインタは定義できません。

```cpp
int num, &ref = num, &*ptrToRef = &ref; // エラー
```

ポインタはオブジェクトなので、ポインタへの参照は定義できます。

```cpp
int num, *ptr = &num, *&refToPtr = ptr; // OK
```

## `const`
### `extern` について
複数のファイルに亘って同じ定数を使う場合は、個々のファイルにそれぞれ定義を書きます。

```cpp:source0.cpp
const int alpha = 12;
int beta = alpha * 2;
```

```cpp:source1.cpp
const int alpha = 12;
int gamma = alpha / 3;
```

一つのファイルだけに定数の定義を書き、他のファイルには宣言だけ書くこともできます。`extern`を使うのですが、宣言だけでなく、定義にも使います。

```cpp:source0.cpp
extern const int alpha = 12;
int beta = alpha * 2;
```

```cpp:source1.cpp
extern const int alpha;
int gamma = alpha / 3;
```

### `const` への参照
`const` への参照で変数への参照を初期化することはできません。

```cpp
int var = 7;
const int con = 8;
const int &ref0 = con;
int &ref1 = con; // エラー
```

型さえ合っていれば、何ででも `const` への参照を初期化することができます。

```cpp
int a = 0;
const int &ref0 = 0;
const int &ref1 = a;
const int &ref2 = a + 1;
```

### `const` なポインタと `const` を指すポインタ
`const` が来る位置で色々決まります。

```cpp
int i = 0;
const int *a = &i;       // const を指すポインタ　（所謂 low-level const）
int *const b = &i;       // const なポインタ　（所謂 top-level const）
const int *const c = &i; // const を指す const なポインタ
```

top-level `const` とは**そのオブジェクト自体**が `const` であることを意味します。だから、top-level `const` を持つオブジェクトの値を変えることは出来ません。

low-level `const` とはそのポインタが指すオブジェクト、またはその参照が指すオブジェクトが　`const` であることを意味します。

### `constexpr`
`constexpr` で宣言されたオブジェクトは返り値の変わらない式で初期化されなければいけません。`constexpr` で宣言されたオブジェクトは top-level `const` になります。

```cpp
constexpr int *ptr0 = nullptr;       // const なポインタ
constexpr const int *ptr1 = nullptr; // const を指す const なポインタ
```

## `typedef`
`typedef` を使って長い型指定子を好きな型指定子に名前を変えることができます。

```cpp
typedef double dd, *dptr, &dref;
dd pi = 3.14;                    // pi は double
dptr piptr = &pi;                // piptr は double を指すポインタ
dref piref = pi;                 // piref は double への参照
```

C++11 では `using` を使って似たようなことができます。

```cpp
using dd = double;              // double
using dptr = double*;           // double を指すポインタ
using dref = double&;           // double への参照
```

`typedef` した型指定子の前に `const` を付けると top-level `const` となります。

```cpp
typedef double dd, *dptr;
dd a = 0;
const dptr p = &a;        // double を指す const なポインタ
```

## `auto`
`auto` を使った宣言で、初期化子が参照だと、型指定子は参照が指すオブジェクトの型となります。参照にしたい場合、識別子の前に `&` を書きます。

```cpp
int a = 0, &r = a;
auto n = r;        // int
auto &n = r;       // int への参照
```

また、`auto` を使うと、初期化子の top-level `const` がなくなります。low-level `const` は残ります。top-level `const` にしたい場合は、`const auto` と書きます。

```cpp
const int c = 0, &r = c; // top-level const な c と low-level const な参照 r
auto d = c;              // int （top-level const がなくなった）
auto e = r;              // int （参照から const int へ変わり、top-level const がなくなった）
auto f = &c;             // const int を指すポインタ （&c は low-level const なので）
const auto g = c;        // const int （const auto による top-level const 指定）
```

## `decltype`
`decltype` は top-level `const` も参照もそのまま型指定子となります。

```cpp
const int a, &ref = a;
decltype(a) i = 12;    // const int
decltype(ref) r = a;   // const int への参照
```

左辺値も左辺値のままだったり。

```cpp
int a, *ptr = &a;
decltype(*ptr) ref = a; // *ptr は int ではなく int への参照 （左辺値）
```

`decltype` に通す変数名に括弧を付けると、それは式として評価されます。括弧を付けなければ、単純に変数として通されます。式として評価されると、変数は参照に変わります。

```cpp
int a = 9, &r = a;
decltype((a)) ref = a; // int への参照
decltype(a) num = 0;   // int
decltype(r) rref = a;  // int への参照 （r がもともと参照なので）
```