PythonistaのためのC++記法入門: それC++ではどう書くの1 ~基本のデータ型~

# はじめに

C++をもう一度真面目に勉強するにあたりPythonで書いていたものをC++ではどう書くのかを中心に書いていく。そのため、この一連の記事はPythonは書けるけどC++は…という人向けに書いている（つもりである）。
内容としては[AtCoderのC++入門](https://atcoder.jp/contests/APG4b)および[cpprefjp - C++日本語リファレンス](https://cpprefjp.github.io/)をだいぶ参考にさせていただいている。

つたない内容であるがご容赦いただきたい。

# 代表的なデータ型
## 整数型

### Pythonではこう書いた

Pythonで数値を扱う際にその表現範囲を気にすることはあまりないだろう。

```python
i = 128
l = 2147483648
```

Python3.5で導入された型ヒントを用いることで静的言語っぽく書くこともできる。変数の定義時に使うことは多くないかもしれないが、思わぬミスを防ぐことはできる。型ヒント自体は後述する関数宣言時のほうが役に立つ印象。

```python
i: int
i = 128  # i: int = 128 と1行でも書ける
```

### C++ではこう書く

一方C++では整数型の表現範囲を考慮しないとオーバーフローで痛い目に合う。

```cpp
int i = 128;
long l = 2147483648;
```

Python3系では型やその上限値を気にすることは（ほぼ）ないだろう（`numpy`などを使う場合は別だが）。
※Python2系では`int`と`long`が存在した。

## 浮動小数点型

### Pythonではこう書いた

```python
f = 0.001
d = 0.001 
```

整数値でも`0.0`などとすれば`float`として扱われる。型ヒントも使えるが、代入する値の型が優先される模様。

```python
f: float
f = 1.  # f: float = 1. と1行でも書ける

# f: float = 1  # こう書くとfはintになってしまう
```

### C++ではこう書く

```cpp
float f = 0.3;
double d;
d = 1.2345;
```

Pythonの`float`はC++だと`double`相当（倍精度）とのこと。

# 文字 / 文字列

Python2系では文字列として`unicode`と`str`の2種類が存在しており非常にややこしかったが、Python3系では文字列は一律`str`で扱われるようになりシンプルになった。

### Pythonではこう書いた

```python
moji = "hello"
print(moji)  # hello が出力される
print(len(moji)) # 文字数である 5 が出力される
letter = "H"  # pythonでは文字列/文字に差はない
#moji[0] = letter  # このような置換はできない
moji = moji.replace(moji[0], letter)  # replaceメソッドを使う必要がある
print(moji)  # Hello が出力される

print(len("Hello")) # 5（文字列をそのまま使える）
print(moji + moji) # HelloHello が出力される（string同士は+演算子で連結可）
```

### C++ではこう書く

Pythonでは文字数によらず`str`として扱われるが、C++では文字数によって`char`または`string`として扱われる。また、Pythonでは文字列を囲む`"`と`'`の違いを意識することは**ほぼ**ないと思われるが、C++では`'`は`char`を、`"`は`string`に対して使われると考える。


```cpp
string moji = "hello";
cout << moji << endl; // hello が出力される
cout << moji.size() << endl; // 5 が出力される
char letter = 'H'; // char型は一文字のみ
moji.at(0) = letter;  // C++ではこのような置換が可能
cout << moji << endl; // Hello が出力される

cout << "Hello"s.size() << endl; // 5（文字列をそのまま使う場合、末尾にsをつける必要あり）
cout << moji + moji << endl; // HelloHello が出力される（string同士は+演算子で連結可）
cout << moji + letter << endl; // HelloH が出力される（stringとcharも+演算子で連結可）
```

#### まとめ

|  |  C++ | Python |
| --- | --- | --- |
| 宣言 / 定義 | string word = "文字列"; | word = "文字列" |
| 任意要素へのアクセス(1) [^1] | word.at(i); [^2] | word[i] [^3] |
| 任意要素へのアクセス(2) [^4] | word[i]; [^2] | 同上 |
| 先頭要素へのアクセス | word.front(); | word[0] |
| 末尾要素へのアクセス | word.back(); | word[-1] |
| 末尾要素の削除 | word.pop_back(); | word = word[:-1] |
| 文字列の長さを取得(1) | word.size(); | len(word) |
| 文字列の長さを取得(2) | word.length(); | 同上 |
| 文字/文字列を追加(1) | word.append(string2); | word += string2 |
| 文字/文字列を追加(2) | word += string2; | 同上 |
| 末尾に*文字*を追加 [^5] | word.push_back(character); | word += character | 
| 文字列の一部を置換 [^6] | word.replace(index1, index2, string2); | word.replace("置換前文字列", "置換後文字列") |
| 指定文字列を検索 [^7] | word.find(string2); | word.find(string2) |
| 指定文字列を末尾から検索 | word.rfind(string2); | word.rfind(string2) | 
| 文字列が空かどうかを判定 | word.empty(); | len(word) == 0 |
| 文字列をクリア | word.clear(); | word = "" |
| 指定の文字列で始まるかを判定する | word.starts_with(string2); [^8] | word.startswith(string2) |
| 指定の文字列で終わるかを判定する | word.ends_with(string2); [^9] |  word.endswith(string2) |
| 指定の文字・文字列が含まれているかを判定する | word.contains(string2); [^10] | string2 in word |


[^1]: C++もPythonも境界チェックを行う。すなわち、範囲外にアクセスしたときにC++では`out_of_range`例外、Pythonでは`IndexError`例外が投げられる
[^2]: C++の`string`の場合、アクセスした要素への値の代入も可能
[^3]: Pythonの`str`の場合、アクセスした要素への値の代入は**不可**
[^4]: 境界チェックは行われず、範囲外のインデックスを指定しても動く可能性がある
[^5]: C++では`char`型、つまり1文字のみの追加に限られる 
[^6]: C++では`index1`から`index2`の範囲の文字列を`string2`で置換する
[^7]: 位置インデックスを返す
[^8]: C++20以降からサポート
[^9]: C++20以降からサポート
[^10]: C++23以降からサポート


## autoによる型推論

C++において、変数の型を初期化子から推論することができる。これにより型を（ある程度）気にせずに変数宣言ができる。Pythonで変数を定義するのとほぼ同じ感覚で変数を用意できる。

### Pythonではこう書いた

```python
a = 120  # intになる
f = 0.001  # floatになる
```


### C++ではこう書く

**初期化を伴う変数宣言の場合**は、`auto`で変数の型を省略できる。

```cpp
auto a = 120; // intになる
auto d = 0.001;  // doubleになる
```