正しい 演算子"<<" の定義の仕方

C++で何らかの型を定義して、その型を文字列に変換したいとき、演算子"<<" をストリームに対し定義してやると便利だ。

class Hoge{
public:
	//たとえば配列のような型だったとする
	size_t size()const{/*略*/}
	int operator[](size_t i)const{/*略*/}
/*略*/
};

Hoge hoge;

std::cout << hoge << std::endl;

よくありがちな失敗は

std::ostream& operator<<(std::ostream& os, const Hoge& rhs){
	//クラスをstringstreamに対し文字列化する
	for(size_t i = 0;i<rhs.size();i++){
		os << hoge[i]
	}
	return os;
}

のような形だろう。これだと、

  • wchar_tに対応しない
  • 途中で失敗したばあいに出力にごみが残る
  • フラグ・ロケール・精度を考慮しない


でこの定義の正しいやり方は以下のようになる

template<typename _CharT, class _Traits>
std::basic_ostream<_CharT, _Traits>& operator<<(std::basic_ostream<_CharT, _Traits>& os, const Hoge& rhs){
	std::basic_ostringstream<_CharT, _Traits> s;//いったんstringstreamを宣言
	
	//フラグ・ロケール・精度をコピー
	s.flags(os.flags());
	s.imbue(os.getloc());
	s.precision(os.precision());

	//クラスをstringstreamに対し文字列化する
	for(size_t i = 0;i<rhs.size();i++){
		s << hoge[i]
	}
	//文字列化し出力
	return os << s.str();
}
  • テンプレートで定義する
  • 出力先からstringstreamに各種情報をコピーする
  • 一度stringstreamに出力する
  • 出力先へstringstreamから文字列化し出力