C++0xで、タプル型の要素を全部展開して出力するoperator<<を書いてみた
C++0xの新機能タプル型ですが、
operator<<がデフォルトで定義されておらず、
tupleの要素数は可変長で、なおかつその長さを調べる方法がないため、
(調べたところ見つからなかっただけです。ご存知の方いらっしゃったら教えてください)
デバッグなどで中身を全て確認したいときにいちいち、
tuple<int, int, int> t{1, 2, 3}; cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
などと書かなくてはいけませんでした。
以下のようにすればまだマシになるように思えるかもしれません。
for(int i = 0; i < 3; i++) cout<< get<i>(t) << " " cout<<endl;
ですが、テンプレート引数は、定数でなくてはならないため、このコードもそもそもコンパイルエラーになってしまいます。
これではデバッグが面倒すぎます。
そこでテンプレートメタプログラミングを使って、
要素を全て出力するオペレータ<<を無理やり定義してみることにしました。
こんな感じになりました。
ソースコード
#define rep(i,n) for(int i=0;i<n;i++) template<class T> ostream& operator<<(ostream &os, vector<T> v){ //ベクタの出力は普通にループで出来る。 os<<"[ "; rep(i,v.size())os<<v[i]<<(i==v.size()-1?" ]":", "); return os; } template<int N, class Tuple, class ...Ts> struct Twrp{ Tuple *x; Twrp(Tuple *x):x(x){} }; template<int N, class Tuple, class H, class ...Ts> ostream& operator<<(ostream &os, Twrp<N, Tuple, H, Ts...> c){ os<<get<N>(*c.x)<<", "<<Twrp<N+1, Tuple, Ts...>(c.x); return os; } template<int N, class Tuple> ostream& operator<<(ostream &os, Twrp<N, Tuple> c){ os<<")"; return os; } template<class ...Ts> ostream& operator<<(ostream &os,tuple<Ts...> t){ os<<"( "<<Twrp<0, tuple<Ts...>, Ts...>(&t); return os; } int main(){ vector<int> v={2,3,4,5,6,7}; tuple<int,string,char,double> t{1,"aaaaaaa",'2',-3.14}; cout<<v<<endl; cout<<t<<endl; return 0; }
実行結果
[ 2, 3, 4, 5, 6, 7 ] ( 1, aaaaaaa, 2, -3.14, )
ちゃんと出力されました。よかった。
[追記]
可変長テンプレート引数の個数は、
sizeof...()演算子を使うことで、sizeof...(Ts)などとして調べられるようです。
それから、上のコードはもう少し簡単に書けて、以下のようになりました。
template<int N,class Tuple> void out(ostream &os,const Tuple &t){} template<int N,class Tuple,class H,class ...Ts> void out(ostream &os,const Tuple &t){ if(N)os<<", "; os<<get<N>(t); out<N+1,Tuple,Ts...>(os,t); } template<class ...Ts> ostream& operator<<(ostream &os, const tuple<Ts...> &t){ os<<"( "; out<0,tuple<Ts...>,Ts...>(os,t); os<<" )"; return os; }