[C++] 関数から複数の戻り値を返す


## C++は関数から一つの値しか返せない？

<pre>
C++ってゅぅのゎ。。

関数から複数の値を返せないの。。。

そして言語仕様も複雑。。。

もぅﾏﾁﾞ無理。。。

Pythonしょ。。。
</pre>

元ネタ:http://d.hatena.ne.jp/keyword/%A4%E2%A4%A5%A5%DE%A5%C2%CC%B5%CD%FD

## C++でも簡単に関数から複数の値を返すことができる！

できるんです！（ただし、C++11以降）

C++11から追加された`std::tuple`を使います。以下はサンプルコードです。

```cpp:tuple.cc
#include <iostream>
#include <string>
#include <tuple>

std::tuple<int, char, std::string> GreatFunction() {
  return std::forward_as_tuple(9, 'q', "qiita");
}

int main() {
  int a;
  char b;
  std::string c;
  std::tie(a, b, c) = GreatFunction();

  std::cout << a << ", " << b << ", " << c << std::endl;
  // 出力 -> 9, q, qiita
  return 0;
}
```

1. 戻り値を`std::tuple`にする
2. `std::forward_as_tuple()`で値を返す
3. `std::tie()`で受け取る

これで関数から任意の数の戻り値を返すことができます。戻り値が２つの場合は`std::pair`でも同じことができます。

受け取る必要のない引数がある場合は`std::ignore`を使って以下のように書きます。

```cpp
std::tie(a, std::ignore, c) = GreatFunction();
```

## 無駄な処理は無い？

このやり方でオブジェクトを戻り値として返す場合、引数でオブジェクトの参照を渡すやり方（`void Function(MyClass &out)`みたいな方法）に比べて無駄な処理が走ります。以下のコードのように自作クラスのオブジェクトを戻り値として返す場合を考えます。

```cpp:myclass.cc
#include <iostream>
#include <tuple>

class A {
 public:
  A() {
    std::cout << "Default constructor" << std::endl;
  }

  A(const A &a) {
    std::cout << "Copy constructor" << std::endl;
  }

  A(const A &&a) {
    std::cout << "Move constructor" << std::endl;
  }

  A& operator=(const A &a) {
    std::cout << "Copy assignment" << std::endl;
    return *this;
  }

  A& operator=(const A &&a) {
    std::cout << "Move assignment" << std::endl;
    return *this;
  }
};

std::tuple<int, A> SuperFunction() {
  A a;
  return std::forward_as_tuple(1, std::move(a));
}

int main() {
  A a;
  std::tie(std::ignore, a) = SuperFunction();
  
  return 0;
}
```

`class A`は各コンストラクタ、代入演算子が呼ばれたときに出力するようになっています。これを実行すると、

<pre>
Default constructor
Default constructor
Move constructor
Move assignment
</pre>

と出力されます。関数内と引数受け取り側でそれぞれDefault constructorが呼ばれ、`return std::forward_as_tuple...`でMove constructorが呼ばれ、`std::tie...`で戻り値を`a`に代入するときにMove assignmentが呼ばれています。つまり、Default constructor１回分とMove constructor, Move assignmentが無駄な処理として実行されてしまいます。なので、コンストラクタやムーブ代入が重い処理のオブジェクトの場合は注意が必要です。また、ムーブ不可なオブジェクトではコピーが走ってしまうのでこの方法は推奨できません。

そのような場合は、戻り値を以下のコードのようにポインタに変更すれば解決します。

```cpp:myclass-pointer.cc
std::tuple<int, std::unique_ptr<A>> ExcellentFunction() {
  std::unique_ptr<A> a(new A());
  return std::forward_as_tuple(1, std::move(a));
}

int main() {
  std::unique_ptr<A> a;
  std::tie(std::ignore, a) = ExcellentFunction();
  
  return 0;
}
```

こうすると`A`のコンストラクタが１回呼ばれるだけなので安心して使えます（`std::unique_ptr`のコンストラクト、ムーブはありますが、大した処理ではないので問題ないでしょう）。

## 余談

C++17では複数の値の受け取り方が以下のようにシンプルになるそうです。（[P0144R2](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0144r2.pdf), [P0217R2](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0217r2.html)）

```
auto [a, b, c] = GreatFunction();
```

`a`,`b`,`c`の宣言が不要になります。これで無駄なコンストラクタが１つ省けるのかな？

---

（追記：@yohhoyさんのコメントより）
C++17から関数の戻り値の部分も`std::forward_as_tuple`を使わずに以下のように簡潔に書けるようになるみたいです。（[N4387](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4387), [LWG2367](http://cplusplus.github.io/LWG/lwg-defects.html#2367)）

```
std::tuple<int, char, std::string> GreatFunction() {
  return {9, 'q', "qiita"};
}
```

## まとめ

* `std::tuple`と`std::tie`を使えば簡単に関数から複数の値を返すことができる
* コンストラクト、ムーブが重いオブジェクトやムーブ不可なオブジェクトを返すときは`std::unique_ptr`を使って返す