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;
}