可変長テンプレート引数と多次元配列コンテナ

#概要
**「C++で多次元配列を作るのは正直めんどくさい」**
そんな悩みを解決するために、自作でコンテナを作ってしまおうって話
今日は多次元配列コンテナ`Multi`と`MultiVector`を実装します、はい

#可変長テンプレート引数
宣言時に`Multi<int,3,4,5,...> a;`と言った感じで、先頭には実体化する型、以降は各次元の要素数を持ち、`int a[3][4][5]`に似たの動作をするように実装しよう。

不定個数のテンプレート引数を取るためには**可変長テンプレート引数**を使うことで解決する。(C++11より)

```cpp
template <class... Args>
class Variable{}
```
ここでの`Args`は**0個以上の型**を意味する。

```cpp
template <std::size_t... Params>
class Variable_size_t{}
```
同様にして、ここでの`Params`は**0個以上のstd::size_t型の定数**を意味する。

```cpp
Variable<int,double,float> v1; //ok
Variable<int,double>       v2; //ok
Variable<int>              v3; //ok
Variable<>                 v4; //ok
Variable<10>               v5; //NG : missmuch argment type 

Variable_size_t<10,20,30> v1; //ok
Variable_size_t<10,20>    v2; //ok
Variable_size_t<10>       v3; //ok
Variable_size_t<>         v4; //ok
Variable_size_t<int>      v5; //NG : missmuch argment type  

```

`Args`や`Prams`はn番目を自由に取り出したりすることはできず、実装側は**展開**することしかできない。それに伴って、**再帰的に処理**するしかない。
まあ、次コードを見ると早い。

```cpp:tuple.hpp
//①
template <class... Args>
class tuple{}

//②
template <class First,class... Body>
class tuple<First,Body...>{
public:
    First value;
    tuple<Body...> child;
}
```
あらゆる型を引数に取れる`tuple`クラスを宣言する（①）
`tuple`に対して**特殊化**、条件は**テンプレート引数が1個以上**（②）
一つ目の型のみ`First`に入り、あとはまとめてBodyに突っ込まれる
メンバ変数childのテンプレート引数が`Body...`となっているが、これは可変長テンプレート引数の**展開**を表す。つまり**先頭を取り除いたものをchildに渡す**ということである。

`tuple<int,float,double>`の展開は以下のようになる。

```cpp
// (1)
class tuple<int,float,double>{
public:
    int value;
    tuple<float,double> child; // (2)
}

// (2)
class tuple<float,double>{
public:
    float value;
    tuple<double> child; // (3)
}

// (3)
class tuple<double>{
public:
    double value;
    tuple<> child; // (4)
}

// (4)
class tuple<>{
}
```

```cpp
tuple<int,float,double,std::string> t;
t.value                   = 10;      //int
t.child.value             = 10.0f;   //float
t.child.child.value       = 10.0d;   //double
t.child.child.child.value = "Hello"; //std::string
```
展開は②が何度も呼ばれ、最後に①が一度だけ呼ばれる仕組みになっている。

`tuple`はテンプレート引数に与えたものを一つづつ持つ型が、言ってしまえば、**即席で構造体が生成できる**。まあ値へのアクセスの仕方が少々面倒だが…
実はtupleは標準で搭載されている。`#include<utility>`と書けば、`std::tuple`でこれより優秀なtupleが使用できる。

ついでに先ほどから **`...`** というもが多用されているが、これは前置であれば**pack演算子**、後置であれば**unpack演算子**と呼ばれたり呼ばれなかったり。
pack演算子は型の圧縮、unpack演算子は型の展開なんて覚えるとよい。

#固定長多次元配列コンテナMulti
こんな感じでまずは固定長のものを作ってみよう
できたものがこれ

```cpp:Multi.hpp
template<class T,std::size_t... Dims>
class Multi{
public:
	typedef T           value_type; //要素のタイプ
	typedef value_type* iterator;   //イテレータ
	typedef value_type  child;      //子配列
public:	
	static const std::size_t   RANK = 0; //次元数
	value_type                 _value;   //要素
public:

	//イテレータ
	iterator begin(){
		return &_value;
	}
	iterator end(){
		return (&_value+1);
	}
	//=演算子で代入可能
	value_type& operator=(const value_type& rhs){
		_value = rhs;
		return _value;
	}
	//value_type型に暗黙的キャスト可能
	operator value_type&(){
		return _value;
	}
};
template<class T,std::size_t First,std::size_t... Dims>
class Multi<T,First,Dims...>{
public:
	typedef T                         value_type; //要素のタイプ
	typedef value_type*               iterator;   //イテレータ
	typedef Multi<value_type,Dims...> child;      //子配列
public:
	static constexpr std::size_t RANK = sizeof...(Dims)+1; //次元数
	child                        _array[First];            //子配列

public:
	//イテレータ
	iterator begin(){
		return _array[0].begin();
	}
	iterator end(){
		return _array[First-1].end();
	}
	//[]演算子でアクセス可能
	child& operator[](const std::size_t& index){
		return _array[index];
	}
};

```
まあこんな感じに、
`begin()`や`end()``typedef``operator`などありますが、その辺りは全部無視で…
`std::size_t`になっても特に変わりはない、先ほどのような再帰でグルングルンとローリング展開しながら`child _array[First];`で自身を次元数だけ持つ。
ついでに`sizeof...(Dims)`で`Dims`の圧縮してる要素の数を展開しないで取得することができる。

`begin()`や`end()``operator`のおまけ機能で`iterator`と`[]`が使用でき、組み込み型に似た動作ができる。

```cpp:main.cpp
Multi<int,3,4,5,6,7,8,9,10> mu;
mu[2][3][4][5][6][7][8][9] = 0;
std::fill(mu.begin(),mu.end(),-1);
std::fill(mu[0].begin(),mu[0].end(),6);
```
まさに`int mu[3][4][5][6][7][8][9][10]`と同様の動作ができる。

**「って、C++でも`int mu[3][4][5][6][7][8][9][10];`は使えるし、そっち使ったほうがええやろボケ」**

まあ…うん…今気づいた…

#可変長多次元配列コンテナMultiVector
この記事書いてる時に`int[3][4][5][6][7][8][9][10]`が標準で使えること思い出したのでは、もう可変長やるしかないですね。

テンプレート引数に渡せるものは**定数** ~~とより高位に評価されるconstexpr変数~~ しかないので、今回は`resize()`関数という**実行時に**大きさを変える関数作ろう。
先のMultiは可変長部分の数で次元数と取得していました。
なので今回宣言の仕方は`MultiVector<型,次元数>`とでもしておきましょうか。

```cpp:MultiVector.hpp
#include <vector>

//可変長多次元配列コンテナ
template<class T,std::size_t Dims>
class MultiVector{
public:
	typedef T                     value_type; //要素のタイプ
	typedef MultiVector<T,Dims-1> child;      //子配列の型
public:
	std::vector<child> _array; //子配列

	//配列の容量の確保
	template<class... Args>
	void resize(std::size_t first ,Args... body){
		_array.resize(first);
		for(child& c:_array){
			c.resize(body...);
		}
	};
	//[]演算子でのアクセス
	child& operator[](const std::size_t& index){
	return _array[index];
	}

};
//配列終端で特殊化
template<class T>
class MultiVector<T,0>{
public:
	typedef T value_type; //要素のタイプ
	typedef T child;      //子配列のタイプ
public:
	T _value; //要素
	
	void resize(){
	};

	//=演算子で代入可能
	value_type& operator=(const value_type& rhs){	
		_value = rhs;
		return _value;
	}
	//value_typeに暗黙的キャスト可能
	operator value_type&(){
		return _value;
	}
};
```

先の`Multi`と同様に再帰呼出しによる実装、`std::vector`を用いることで可変長配列にした。
可変長テンプレート引数はメンバテンプレート関数にも使用できる。`resize()`の`Args`がすべて`std::size_t`であることは、この時点では保証されていないが、再帰呼出しかつ終端が引数なしであることによって`std::size_t`以外のものを入れると、どこかでエラーを吐く仕組みになっている。

また、このデータ構造はすべての要素がメモリ上で連続しているとは限らない。よって単純に先頭と終端のアドレスを取るだけでiteratorになるMultiとは違い、より高度な制御構文を持つiteratorが必要になるのでMultiVectorはiteratorをサポートしていない。

#まとめ

可変長テンプレート引数を用いることで無限の引数を扱え、よりテンプレートが豊かになる反面、実装は再帰とテンプレートの特殊化を多く使用するため、実装は少々難しくなり可読性も落ちる。
可変長テンプレートは関数にも使用できるので、これでprintfモドキをつくることももちろんできるので、ぜひ挑戦してみてほしい。

なんで正月からこんな記事書いてるんだ…

---
追記:2016年7月20日

* Multiクラスのイテレータのendの処理を修正
* RANKメンバ変数の計算式を修正