[C++17]構造化束縛について調べてみた

## きっかけ
以前、Pythonでカイ二乗検定を行ったときに、下記コードを使用していた。今改めてコードを見た時に、Pythonには多重代入（複数の変数に値を代入する）があったことを思い出した。多重代入について調べてみると、Python以外にも、Ruby、Scala、Perlなど多くの言語で、同じもしくは似た機能があるようです。

```python:Python
from scipy import stats
#カイ二乗検定
#多重代入をしている
squared,p,dof,ef = stats.chi2_contingency(dat)
```

## [C++17]構造化束縛
C++でも多重代入出来れば良いのにと思い調べてみると、C++17で[構造化束縛](https://cpprefjp.github.io/lang/cpp17/structured_bindings.html)という機能が実装されていました。早速どんなものなのか試してみました。

### 定義
> 「構造化束縛 (structured bindings)」は、組やタプル、配列や構造体を分解して各要素を取り出す機能である。この機能は、他の言語では「多重代入 (mutiple assignment, Python言語やRuby言語)」や「分割代入 (Destructuring assignment, JavaScript言語)」といった名称で知られている。
(引用先) [cpprefjp - C++日本語リファレンス：構造化束縛](https://cpprefjp.github.io/lang/cpp17/structured_bindings.html)

### 使用環境
+ Visual Studio Community 2017
+ コンパイル時有効になっているバージョン /std:c++latest

※Visual Studio 2017のC++の言語標準はデフォルトでC++14（/std:c++14）になっているため、C++17（/std:c++latest）に設定しないとエラーになります。

### 使用コード
今回は、私がC++でよく使うstd::pair、std::map、std::unordered_mapを用いて、試してみました。他にも、[cpprefjp - C++日本語リファレンス：構造化束縛](https://cpprefjp.github.io/lang/cpp17/structured_bindings.html)によると、配列やstd::tupleやクラスのPublicメンバ変数にも使用可能とあるため、多くの場面で使えそうな機能である。（クラスのprivateメンバ変数、静的メンバ変数、定数は対応していない）

```cpp:main.cpp
int main(){

    //std::pair
    std::pair<int,std::string> testPair{0,"test" };
    auto[key, value] = testPair;
    std::cout << key << "," << value << std::endl;
    //出力結果
    //0,test

    //std::map
    std::map<int, std::string> mapHash = {
    { 0,"red" },
    { 1,"green" },
    { 2,"blue" },
    };
    //いままではこの書き方
    for (const auto& d : mapHash)
	{
		std::cout << d.first << "," << d.second << std::endl;
	}
    //C++17ではfor文内でも使用出来る！！
    for (const auto& [key2, value2] : mapHash){
    	std::cout << key2 << "," << value2 << std::endl;
    }
    //出力結果
    //o,red
    //1,green
    //2,blue

    //std::unordered_map
    std::unordered_map<int, std::string> unordered_mapHash = {
    { 0,"red" },
    { 1,"green" },
    { 2,"blue" },
    };
    for (const auto& [key3, value3] : unordered_mapHash){
    	std::cout << key3 << "," << value3 << std::endl;
    }
    //出力結果
    //o,red
    //1,green
    //2,blue
}
```
ただし、当たり前かと思われるかもしれないが、使用しない変数を指定した場合、エラーが出るため、注意が必要です。

```cpp:main.cpp
int main(){
    std::pair<int,std::string> testPair{0,"test" };
    //使用しない変数があるため、エラーが発生する
    auto[key, value,bug] = testPair;
}
```
他にも、自作クラス内で定義した変数を全取得したいときに、下記みたいに実装することも可能である。いままでの私のコードでは、自分でわかりやすくするために複数のローカル変数を使用していたが、構造化束縛により、変数宣言とデータ構造の分解が同時出来ることから、（自分の中では特に）このようなコードが減ると思われる。

```cpp:main.cpp
//自作クラス
class TestAccessor
{
public:
	TestAccessor() {}

	void AddData(const int key, const std::string &value)
	{
		_data[key] = value;
	}

public:
	using iterator = std::map<int, std::string>::iterator;
	using constIterator = std::map<int, std::string>::const_iterator;

    //std::mapのイテレータを使用する
	iterator begin() {
		return _data.begin();
	}

	iterator end() {
		return _data.end();
	}

	constIterator begin() const{
		return _data.begin();
	
	constIterator end() const {
		return _data.end();
	}

private:
	std::map<int, std::string> _data;
};

int main()
{
    TestAccessor accessor;
	accessor.AddData(0, "red");
	accessor.AddData(1, "green");
	accessor.AddData(2, "blue");

    //分かりやすくするために、ローカル変数に代入していた
	for (const auto& data : accessor)
	{
		int key = data.first;
		std::string value = data.second;
		std::cout << key << "," << value << std::endl;
	}
    //ローカル変数を使用しなくていい！！
    //わかりやすくなる
	for (const auto& [key, value] : accessor)
	{
		std::cout << key << "," << value << std::endl;
	}
    //出力結果
    //o,red
    //1,green
    //2,blue

}
```

## 結果
いままで、C++のレガシーな書き方を多く使用してきた。しかし、C++の新しいバージョンで増えた機能、書き方を使用することで、可読性が上がり、自作故のバグが減ると思います。これから新しいバージョンで追加された機能も追いかけていきます。

私はまだまだC++の機能等について勉強不足なので、何か間違いなどあればコメントで情報提供よろしくお願いします。


## 参考
+ [cpprefjp - C++日本語リファレンス：構造化束縛](https://cpprefjp.github.io/lang/cpp17/structured_bindings.html)
+ [Rubyの多重代入あれこれまとめ](https://qiita.com/yancya/items/c557864f307d429bbde4)
+ [Effective Scala：Destructuring bindings](http://twitter.github.io/effectivescala/#Functional%20programming-Destructuring%20bindings)
+ [Perl基礎入門：第3章 リストと配列](http://www.kent-web.com/perl/chap3.html)