はじめに
競プロやってると、多次元のvectorをよく使うことがあります。非常に便利なんだけど、宣言がめんどくさい。
例えば、3次元のvectorを宣言しようとすると、
vector<vector<vector<int>>>v(10,vector<vector<int>>(10,vector<int>(10,1000)));
こうなります。
4次元はもう書く気すらなくなってしまいます。しかしvectorsのテンプレートを用いると、
auto v = vectors(10,10,10,3);
このように簡単に書くことができます。
個の引数に対して、最後の数値を初期値として次元のvectorを生成できます。
今回はこのテンプレートを詳しく見ていくことにします(勉強を兼ねて)
vectorsテンプレート
template<typename Head, typename Value>
auto vectors(const Head &head, const Value &v) {
return vector<Value>(head, v);
}
template<typename Head, typename... Tail>
auto vectors(Head x, Tail... tail) {
auto inner = vectors(tail...);
return vector<decltype(inner)>(x, inner); }
vectorsのテンプレートは2つのvectorsという関数から成り立っています。
これを詳しく見ていきます。
可変引数テンプレート
任意のNについてvectorを生成するので、引数は毎度変化します。
これに対応するために、可変引数テンプレート*1が用いられています。
サンプルコードを見て見ましょう。
#include<bits/stdc++.h>
using namespace std;
template<class ...Args>
void func(Args... arg){
cout << sizeof...(arg) << endl;
}
template<class Head, class ...args> void func2 (Head a,args... b){
cout << a << endl;
cout << sizeof...(b) << endl;
}
signed main(){
func(1,2,3,4,5,6,7,8);
func2(1,2.2,"3",'4');
}
可変引数テンプレートでは、任意の型と任意の引数をテンプレートとして利用することができます。
上記のfunc関数では
・Argsがテンプレートパラメータパック
・argsをが関数パラメータパック
となっています。それぞれ、推論された型、引数が格納されています。
関数内でパラメータパックを用いる際は ... を用いて展開します。
func2に注目してみると、引数として渡された引数が、Head 型の a と args型のbに分割されています。
この関数を繰り返し用いると、やがてargs...の引数は一つになります。
勘がいい方はすでに気づいているかもしれませんが、これは繰り返し処理に用いることができます。
具体例を示します。
#include<bits/stdc++.h>
using namespace std;
template<class Head, class args> void func2 (Head a,args b){
cout << a << endl;
cout << b << endl;
}
template<class Head, class... args> void func2 (Head a,args... b){
func2(b...);
}signed main(){;
func2(1,2.2,"3",'4');
}
複数の引数が渡された関数は、再帰的にfunc2関数を呼び、最後に引数の引数の数は2つになります。
このように、関数をオーバーロードすることで、タグディスパッチによって最適な関数が呼び出されます。
decltypeについて
上記の知識とautoがsyntax sugarであることがわかれば、ほとんど中身が理解できる…かもしれませんが、最後にdecltypeだけ説明しておきます。
decltypeとは、指定した式から型取得する機能です。
#include<bits/stdc++.h>
using namespace std;
signed main(){
cout << sizeof(decltype(2.2+ 3.4)) << endl;
cout << sizeof(decltype('a' )) << endl;
cout << sizeof(decltype(2+1))<<endl;
}
vectorsテンプレートでは、decltypeで取得した型とするvectorを返すことで、入れ子構造を達成しています。