メニュー
ブログ更新履歴
コンテンツ更新履歴
リンク
  • Magome
  • クラウドベースのMIDIシーケンサ
    音楽制作に興味のある方を対象に、スタンドアロンでも使え、ネットならではの面白さも兼ね備えた音楽制作アプリの提供を目指しています。
twitter

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

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

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

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

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

コード anchor.png

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版

}
Page Top

追記履歴 anchor.png

  • CString 対応コードを追加しました 2019/5/15

Front page   Freeze Diff Backup Copy Rename ReloadPrint View   New Page Page list Search Recent changes   Help   RSS of recent changes (RSS 1.0) RSS of recent changes (RSS 2.0) RSS of recent changes (RSS Atom) Powered by xpWiki
Counter: 1537, today: 4, yesterday: 5
Princeps date: 2018-02-12 (Mon) 01:13:17
Last-modified: 2019-05-15 (Wed) 12:01:00 (JST) (207d) by takatsuka