目的
CSV形式やTSV形式で出力したい時、区切り文字を毎回書くのはちょっと面倒。
for (size_t i = 1; i < 10; i++) {
std::cout
<< "[csv] "
<< i
<< ", " << std::string(i, 'x')
<< ", " << std::boolalpha << (i % 2 == 0)
<< "\n";
}
次のように書けると気分が良い。
for (size_t i = 1; i < 10; i++) {
make_auto_sep(std::cout, "[csv] ", ", ", "\n")
<< i
<< std::string(i, 'x')
<< std::boolalpha << (i % 2 == 0);
}
という類のものを何度も再発明していることに気付いたので、纏めたものをメモ。
コード
# include <iostream>
# include <string>
// 出力ストリームに区切り文字を自動で挿入するラッパクラス
template<class CharT, class Traits, class Sep, class End>
class AutoSep {
std::basic_ostream<CharT, Traits>& os_;
const Sep& sep_;
const End& end_;
bool is_first_ = true;
public:
template<class Start>
AutoSep(
std::basic_ostream<CharT, Traits>& os,
const Start& start,
const Sep& sep,
const End& end) : os_(os), sep_(sep), end_(end)
{
os_ << start;
}
~AutoSep()
{
os_ << end_;
}
// マニュピレータは区切り文字を入れない
AutoSep& operator<<(std::ios_base& (*func)(std::ios_base&))
{
os_ << func;
return *this;
}
// 二回目から区切り文字を入れる
template<class T>
AutoSep& operator<< (const T& v)
{
if (is_first_) {
os_ << v;
is_first_ = false;
} else {
os_ << sep_ << v;
}
return *this;
}
};
// コンストラクタの型推論用
template<class CharT, class Traits, class Start, class Sep, class End>
AutoSep<CharT, Traits, Sep, End> make_auto_sep(
std::basic_ostream<CharT, Traits>& os,
const Start& start,
const Sep& sep,
const End& end)
{
return AutoSep<CharT, Traits, Sep, End>(os, start, sep, end);
}
int main()
{
for (size_t i = 1; i < 10; i++) {
make_auto_sep(std::cout, "[csv] ", ", ", "\n")
<< i
<< std::string(i, 'x')
<< std::boolalpha << (i % 2 == 0);
}
return 0;
}
出力
[csv] 1, x, false
[csv] 2, xx, true
[csv] 3, xxx, false
[csv] 4, xxxx, true
[csv] 5, xxxxx, false
[csv] 6, xxxxxx, true
[csv] 7, xxxxxxx, false
[csv] 8, xxxxxxxx, true
[csv] 9, xxxxxxxxx, false