構造化束縛:範囲ベースforでindexも取得する

#はじめに
C++17から使える構造化束縛を使えばindex付きの範囲ベースforをいい感じに書けるのでは？って思ったのでまとめとく

**10/31追記　constにしたい時は`as_const`で良かった**

#範囲ベースでindex取得

もとのイテレーターの値への参照とindexを返すWithIndexIteratorを作成し、
それを返すclassを作る


```cpp:Range.hpp
#pragma once

#include<iterator>

namespace range
{
	template<class Range>
	using range_iterator_t = decltype(std::begin(std::declval<Range&>()));

	template<class Range>
	using range_const_iterator_t = decltype(std::cbegin(std::declval<Range&>()));

	namespace detail
	{
		//pair(普通のstd::pairでも良い)
		template<class T>
		struct WithIndexPair
		{
			T value;
			const std::size_t index;
		};
		//イテレーター
		template<class It>
		class WithIndexIterator
		{
		public:
			using iterator_category = std::bidirectional_iterator_tag;
			using difference_type = std::size_t;
			using value_type = WithIndexPair<decltype(*std::declval<It>())&>;
			using pointer = value_type*;
			using reference = value_type&;
		private:
			It m_iterator;
			std::size_t m_index;
		public:
			WithIndexIterator(It it, std::size_t index) :
				m_iterator(it),
				m_index(index)
			{}

			value_type operator *()const
			{
				return { *m_iterator, m_index };
			}
			value_type* operator ->()const
			{
				return &*(*this);
			}
			WithIndexIterator& operator ++()
			{
				++m_iterator;
				++m_index;
				return *this;
			}
			WithIndexIterator& operator --()
			{
				--m_iterator;
				--m_index;
				return *this;
			}
			bool operator ==(const WithIndexIterator& other)const
			{
				return m_iterator == other.m_iterator;
			}
			bool operator !=(const WithIndexIterator& other)const
			{
				return m_iterator != other.m_iterator;
			}

		};
		//レンジ
		template<class Range>
		class WithIndexRange
		{
			using iterator = WithIndexIterator<range_iterator_t<Range>>;
			using const_iterator = WithIndexIterator<range_const_iterator_t<Range>>;

		private:
			Range m_range;
		public:

			WithIndexRange(Range&& range) :
				m_range(std::forward<Range>(range))
			{}

			iterator begin()
			{
				return { std::begin(m_range),0 };
			}
			iterator end()
			{
				return { std::end(m_range) , std::size(m_range) };
			}

			const_iterator begin()const
			{
				return const_iterator{ std::begin(m_range),0 };
			}
			const_iterator end()const
			{
				return const_iterator{ std::end(m_range) , std::size(m_range) };
			}

			std::size_t size()const
			{
				return std::size(m_range);
			}

		};
	}

	//添え字付き
	constexpr struct _WithIndex_OP
	{
		template<class Range>
		auto operator()(Range&& v)const
		{
			return detail::WithIndexRange<Range>(std::forward<Range>(v));
		}
		template<class Range>
		friend auto operator -(Range&& v, _WithIndex_OP op)
		{
			return op(std::forward<Range>(v));
		}
	}withIndex;


}



```


以下みたいに値とindexをとることができる。

また、メンバの参照型はconstで受け取っても変更可能なので注意
constにしたい場合は`std::as_const`を使うことで使い分けができる(右辺値は無理だが…)

```cpp:main.cpp
int main()
{
	std::vector<int> v{ 1,2,3 };
	
	//添え字つき
	for (auto&&elm: v - range::with_index)
	{
		std::cout << "Value :" << elm.value <<
					" Index :" << elm.index << std::endl;
	}
	//添え字つき　const版
	for (auto&&elm : std::as_const(v) - range::with_index)
	{
		//エラー
		//elm.value += 1;
	}
	return 0;
}

```
ここまではC++17じゃなくてもいい

# 構造化束縛

C++17から使える構造化束縛が便利

```cpp:main.cpp
decltype(auto) test1()
{
	return std::make_tuple("Hellow", 1);
}
decltype(auto) test2()
{
	struct
	{
		int m_x;
		int m_y;
	}ret{33,4};
	return ret;
}
decltype(auto) test3()
{
	return std::make_pair(1,0.5);
}


int main()
{

	{
		auto [str, i] = test1();		//tuple
	}
	{
		auto [x, y] = test2();			//struct
	}
	{
		int raw_ar[3] = { 1,2,3 };
		auto[x, y, z] = raw_ar;			//raw array
	}
	{
		std::array<int, 3> ar{ 4,5,6 };	//stl array
		auto [x, y, z] = ar;
	}
	{
		auto [i, d] = test3();			//pair
	}	

	return 0;
}



```
`auto&,const auto&,auto&&`などでも受け取れる
`std::tie`を楽にした感じ

で、この機能と先ほどのindex取得を組み合わせれば
下みたいにかける

```cpp:main.cpp


int main()
{
	std::vector<int> v{ 1,2,3 };
	
	//添え字つき
	for (auto&&[elm,i]: v - range::with_index)
	{
		std::cout << "Value :" << elm <<
					" Index :" << i << std::endl;
	}
	return 0;
}

```

わりと好み

#おまけ

関係ないけど逆順範囲forなども作ってみた

```cpp:main.cpp

int main()
{

	std::vector<int> v{ 1,2,3 };

	for (auto&& elm: v - range::reverse)
	{
		std::cout << elm;
	}

	return 0;
}

```
###ソースコード
https://gist.github.com/tyanmahou/45341370b330f5cc5cabe850838031af