PythonistaのためのC++記法入門: それC++ではどう書くの6 ~関数定義1~

[PythonistaのためのC++記法入門: それC++ではどう書くの5](https://qiita.com/nctp/items/5088cd08354b4300bfc6)の続き。今回からは関数について。

# 関数関連

## 関数の基本

例として
1. **整数型の2値**を受け取ってその和（整数型）を返す関数
2. **整数型の2値**を受け取ってその平均（**整数型とは限らない**）を返す関数
を考える。

### Pythonではこう書いた

```python
def sum(x, y):
    ans = x + y
    return ans

def average(x, y):
    ans = sum(x, y) / 2.
    return ans

def main():
    a = 10
    b = 20
    print(sum(a, b))  # 30 が出力される
    print(average(a, b))  # 15.0 が出力される

if __name__ == '__main__':
    main()
```

Pythonでは引数の型も、返り値の型も何も気にしなくてよい。その代わり、この場合だと引数や返り値の型が狙い通りになるか確証はない。

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

```cpp
#include <bits/stdc++.h>
using namespace std;

int sum(int a, int b) {
  int ans;
  ans = a + b;
  return ans;
}

float average(int a, int b) {
  float ans;
  ans = sum(a, b) / 2.;
  return ans;
}

int main()
{
  int a = 10;
  int b = 20;
  cout << sum(a, b) << endl;  // 30 が出力される
  cout << average(a, b) << endl;  // 15 が出力される（表記上int型に見えるがtypeidはf,つまりfloat型）
}

```

一方C++では引数や返り値の型を考慮した上で関数を定義する必要がある。
整数型の2値の平均は常に整数型になるとは限らないため、`float`を返り値に取るように関数を定義しないと所望の答えが得られない。

### （一応）Pythonでもこう書ける

Python3.5以降で導入された型ヒントを用いることで型を考慮した関数定義ができるようになった。スクリプトが複雑化し、どの関数がどういった意味を持ち、何を引数に取って何を返すべきかがわかりにくくなってきたときに地味に便利である。

```python
def sum(x: int, y: int) -> int:
    ans = x + y
    return ans

def average(x: int, y: int) -> float:
    ans = sum(x, y) / 2.
    return ans
```

## 返り値がない関数

PythonでもC++でも`return`文を省略できるのは同じ。

### Pythonではこう書いた

```python
def display_string(x):
    print(x)

def main():
    display_string("This will be displayed.")

if __name__ == '__main__':
    main()
```

実質的に`None`を返している。型ヒントを使う場合は`def func(x) -> None:`と書く。

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

```cpp
#include <bits/stdc++.h>
using namespace std;

void display_string(string x) {
    cout << x << endl;
}

int main()
{
  display_string("This will be displayed.");  // This will be displayed. と出力される
}
```

C++では関数定義時に返り値の情報が必要なので、このような場合は`void`を充てる（個人的にこのワードチョイスは絶妙だと思う）。

## デフォルト値を指定する

### Pythonではこう書いた

```python
def greet(message, name="John", goal=1):
    print(message, end=" ")
    print(f"My name is {name}. I want to be No.{goal}.")

def main():
    greet("Yeah!!!")
    greet("Hi.", "Mike")
    greet("Well...", "Bob", 2)

if __name__ == '__main__':
    main()
```

```cpp
#include <bits/stdc++.h>
using namespace std;

void greet(string message, string name="John", int goal=1) {
    cout << message;
    cout << " My name is " << name << ". I want to be No." << goal << "." << endl;
}

int main() {
    greet("Yeah!!!");
    greet("Hi.", "Mike");
    greet("Well...", "Bob", 2);
}
```

ほとんど書き方や使い方は同じ。出力はいずれも以下のようになる。

```text
Yeah!!! My name is John. I want to be No.1.
Hi. My name is Mike. I want to be No.1.
Well... My name is Bob. I want to be No.2.
```


### オーバーロード(overload)

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

C++では同名の関数を定義できる。これはPythonでは（異なる名前空間を用いない限りは）できない。
オーバーロードによる多重定義ができる関数は、**「引数の型」か「引数の数」が異なる場合である。**
よって、以下のように二つの`sum`関数を用意することができる（意義は薄い）。

```cpp
int sum(int a, int b){
  int ans;
  ans = a + b;
  return ans;
}

int sum(int a, int b, int c){
  int ans;
  ans = a + b + c;
  return ans;
}
```

## ラムダ式

### Pythonではこう書いた

```python
my_min = lambda x, y: x if x < y else y
```

すなわち

```python
関数名 = lambda 引数1, 引数2, ...: 処理
```

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

```cpp
auto my_min = [](int a, int b) {
  int answer= a < b ? a : b;
  return answer;
};
```

すなわち

```cpp
auto 関数名 = [](引数1の型 引数1, 引数2の型 引数2, ...) {
  処理;
  return 返り値;
};
```