std::tupleを使って複数の値を返す

忘れる前にメモ．

## 設定

- 関数の返り値として複数の値を返したい．
- 例えば，何かの処理を行い，これに成功したら返って来た値を使用して処理，失敗したら何もしない，ということができるような簡単なコードを書きたい．
- 返り値を受ける代わりにポインタを渡すのは関数インターフェースの見栄えがよろしくない．
- 適当にエンコーディングを考えて，一つの返り値に複数の値の意味を埋め込んでしまうのは，もっとよろしくない．
- 値が有効か，無効かを示すだけならBoost.Optionalがあるけど，標準ライブラリだけでどうにかしたい．
- std::optionalが標準に入るのはまだ先のようだ…
- C++11の範囲だけでどうにかする．

## サンプルコード

とりあえず，サンプルを書きましたが，この例だとイテレータ使え，と言われそうですね．とりあえずパっと思い付いたものがこれなので，もっと良いサンプルがあればそれに書き直します．

返り値をstd::tupleにする場合のポイントとして，std::tieで返り値を受ける変数を指定する場合はconst宣言できない．
constな変数に返り値を代入したい場合は，普通にconst std::tuple<...>型の変数で受けて，std::get<n>で値を参照することになる．ちょっと打つのが面倒かも．

有効か無効かを表わしたい場合，std::optionalが使えるようになったら，それを使った方が良さそう．あるいはおとなしくBoost.Optionalを使う．

```cpp
#include <tuple>

#include <iostream>
#include <vector>

namespace before {

long find(const std::vector<int>& vec, const int a)
{
	for(size_t i = 0; i < vec.size(); i++) {
		if (vec[i] == a) {
			return i;
		}
	}
	return -1;
}

void demo()
{
	const std::vector<int> vec = {0, -1, 1, 2, -2, 3};

	const int a = 2;
	const long b = find(vec, a);
	if (b < 0) {
		std::cout << a << " is not contained in vec." << std::endl;
	} else {
		std::cout << a << " is contained at " << b << " in vec." << std::endl;
	}

	const int c = -5;
	const long d = find(vec, c);
	if (d < 0) {
		std::cout << c << " is not contained in vec." << std::endl;
	} else {
		std::cout << c << " is contained at " << d << " in vec." << std::endl;
	}
}

}

namespace after {

std::tuple<size_t, bool> find(const std::vector<int>& vec, const int a)
{
	for(size_t i = 0; i < vec.size(); i++) {
		if (vec[i] == a) {
			return std::forward_as_tuple(i, true);
		}
	}
	return std::forward_as_tuple(0, false);
}

void demo()
{
	const std::vector<int> vec = {0, -1, 1, 2, -2, 3};

	const int a = 2;
	size_t b;
	bool c;
	std::tie(b, c) = find(vec, a);
	if (c) {
		std::cout << a << " is contained at " << b << " in vec." << std::endl;
	} else {
		std::cout << a << " is not contained in vec." << std::endl;
	}

	const int d = -5;
	size_t e;
	bool f;
	std::tie(e, f) = find(vec, d);
	if (f) {
		std::cout << d << " is contained at " << e << " in vec." << std::endl;
	} else {
		std::cout << d << " is not contained in vec." << std::endl;
	}
}

template<class T, class V, class Option>
void puts_result(const T& value, const std::tuple<V, Option>& result) {
	if (std::get<1>(result)) {
		std::cout << value << " is contained at " << std::get<0>(result) << "." << std::endl;
	} else {
		std::cout << value << " is not contained." << std::endl;
	}
}

void demo2()
{
	const std::vector<int> vec = {0, -1, 1, 2, -2, 3};

	const int a = 2;
	const std::tuple<size_t, bool> b = find(vec, a);
	puts_result(a, b);

	const int c = -5;
	const std::tuple<size_t, bool> d = find(vec, c);
	puts_result(c, d);
}

}

int main()
{
	before::demo();
	after::demo();
	after::demo2();
}
```
- [[Wandbox]三へ( へ՞ਊ ՞)へ ﾊｯﾊｯ](http://melpon.org/wandbox/permlink/7C5PLLYdv6yE46L7 "[Wandbox]三へ( へ՞ਊ ՞)へ ﾊｯﾊｯ")

## 参考文献

- [A proposal to add a utility class to represent optional objects (Revision 2)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3527.html "A proposal to add a utility class to represent optional objects (Revision 2)")
    - リファレンス実装有り→[akrzemi1/Optional](https://github.com/akrzemi1/Optional/ "akrzemi1/Optional") (問題無く動くかどうかは未検証です)
- [Twitter / Flast_RO: @t_teruya std::tupeに対してstd::fo ...](https://twitter.com/Flast_RO/status/417379848017825794 "Twitter / Flast_RO: @t_teruya std::tupeに対してstd::fo ...")
- [Twitter / Flast_RO: @t_teruya std::tieは大体そんな感じの目的で ...](https://twitter.com/Flast_RO/status/417384572251148288 "Twitter / Flast_RO: @t_teruya std::tieは大体そんな感じの目的で ...")