ページへ戻る

− Links

 印刷 

技術系備忘録​/C++​/Boost​/boost.formatを使った文字列フォーマット。printf系関数を置き換え のバックアップソース(No.2) :: シンクリッジ

xpwiki:技術系備忘録/C++/Boost/boost.formatを使った文字列フォーマット。printf系関数を置き換え のバックアップソース(No.2)

« Prev[4]  Next »[5]
C++ だと文字列をフォーマットするコードって結構大変です。
C++11(14) になって色々な選択肢は増えたんですが、いまいち決定打に欠けると言いますか・・。

というわけで boost です。boost::format を使った文字列フォーマットです。
% で繋げることなく、可変引数テンプレートを使って printf 風に使えるようにしてみました。
boost::format の機能のおかげで、型安全で例外が発生することもないようにしています。

&font(80%){例えばアプリで処理失敗が発生したときに、アプリログを残す際に sprintf などを使ってフォーマットしてるような場合、その書式をミスっていたりすると、アプリが落ちたりしちゃいます。&br;レアケース(処理失敗)を考慮したコードを書いたつもりが、再現率が低く修正しにくい致命的なバグを生んでしまったりするので、できれば、こういう箇所は特に安全に書いておきたいなと思う次第。&br;というわけで、};

printf 系の関数は(windows の CString::Format とかも)使わないほうが安全です。
がしかし printf 系の使いやすさは捨て難いです。慣れちゃってもいるし。

そんなわけで printf 風の書き方も出来てしまう boost::format はすごく便利です。
開発者の方に感謝しつつ使わせていただこうと思います。

* コード [#rad4fc7a]
#prettify{{
namespace String
{

template <class CharT> std::basic_string<CharT> Format(const boost::basic_format<CharT> &format)
{
	return format.str();
}

#ifdef _MSC_VER	// VisualC++ の CString 対応
template <class CharT,class... Tail> std::basic_string<CharT> Format(boost::basic_format<CharT> &format,CStringA& head,Tail&&... tail)
{
	return Format<CharT>( format % std::basic_string<CharT>(head), tail... );
}
template <class CharT,class... Tail> std::basic_string<CharT> Format(boost::basic_format<CharT> &format,const CStringA& head,Tail&&... tail)
{
	return Format<CharT>( format % std::basic_string<CharT>(head), tail... );
}
template <class CharT,class... Tail> std::basic_string<CharT> Format(boost::basic_format<CharT> &format,CStringW& head,Tail&&... tail)
{
	return Format<CharT>( format % std::basic_string<CharT>(head), tail... );
}
template <class CharT,class... Tail> std::basic_string<CharT> Format(boost::basic_format<CharT> &format,const CStringW& head,Tail&&... tail)
{
	return Format<CharT>( format % std::basic_string<CharT>(head), tail... );
}
#endif

template <class CharT,class Head,class... Tail> std::basic_string<CharT> Format(boost::basic_format<CharT> &format,Head&& head, Tail&&... tail)
{
	return Format<CharT>( format % head, tail... );
}

template <class CharT,class... Args> std::basic_string<CharT> Format(const CharT *lpszFormat,Args&&... args)
{
	boost::basic_format<CharT> format;
	format.exceptions( boost::io::no_error_bits );	// 例外を発生させない
	format.parse(lpszFormat);
	return Format<CharT>(format,args...);
}

}

// 使い方例
int main()
{

	std::string s0 = String::Format( "%s %dSX SR%dDE%s", "日産", 180, 20, "T" );	// s0 = "日産 180SX SR20DET"

	std::wstring ws0 = String::Format( L"BNR%d RB%dDE%s", 32, 26, L"TT" );			// ws0 = L"BNR32 RB26DETT"  std::wstring も可です

	std::string s1 = String::Format( "%s %dSX SR%dDE%s", 180, 20, "T", L"日産" );	// s1 = "180 20SX SRTDE01909714"  例外発生しません

	const std::string s2a = u8"トヨタ";
	const std::string s2b = "1JZ-GTE";
	std::string s2c = String::Format( "%s jzx90 %s", s2a, s2b );	// s2c = "トヨタ jzx90 1JZ-GTE"  std::string をそのまま書けます。 c_str() は不要です。便利!

	CString t0(_T("マツダ"));
	const CString t1(_T("13B-T"));
	auto tr = RLib::String::Format(_T("%s FC3S %s"),t0,t1);		// tr = _T("マツダ FC3S 13B-T")  vc の CString版

}
}}

* 追記履歴 [#p57d9c21]
- CString 対応コードを追加しました 2019/5/15

« Prev[4]  Next »[5]