虽然我可以理解重载流运算符的想法,但我会质疑手头问题的做法。
1.面向对象的方法
如果您愿意写入.csv 文件,那么每一行的格式应该与其他行完全相同?不幸的是,您的流操作员没有检查它。
我认为您需要创建一个Line 对象,而不是流式传输,并且在将它们写入文件之前验证每个字段(并以正确的格式写入它们)。虽然不那么时髦,但您将有更多机会在这里实现强大的实现。
假设(例如)您要输出 2 个整数和一个字符串:
class Line
{
public:
Line(int foo, int bar, std::string firstName):
mFoo(foo), mBar(bar), mFirstName(firstName)
friend std::ostream& operator<<(std::ostream& out, const Line& line)
{
return out << line.mFoo << ',' << line.mBar << ','
<< line.mFirstName << std::endl;
}
private:
int mFoo;
int mBar;
std::string mFirstName;
};
而且使用它仍然非常简单:
std::cout << Line(1,3,"Tom") << Line(2,4,"John") << Line(3,5,"Edward");
2。想玩得开心吗?
现在,这可能看起来很乏味,您可能希望玩,但仍然可以控制所写的内容......好吧,让我将模板元编程引入战斗;)
这是预期的用途:
// Yeah, I could wrap this mpl_::vector bit... but it takes some work!
typedef CsvWriter< mpl_::vector<int,int,std::string> > csv_type;
csv_type(std::cout) << 1 << 3 << "Tom" << 2 << 4 << "John" << 3 << 5 << "Edward";
csv_type(std::cout) << 1 << 2 << 3; // Compile Time Error:
// 3 is not convertible to std::string
现在这会很有趣吧?它将格式化该行并确保验证的度量......人们总是可以使设计复杂化,以便它做更多的事情(比如为每个字段或整行注册验证器等......)但它已经足够复杂了。
// namespace mpl_ = boost::mpl
/// Sequence: MPL sequence
/// pos: mpl_::size_t<N>, position in the Sequence
namespace result_of {
template <class Sequence, class pos> struct operator_in;
}
template < class Sequence, class pos = mpl_::size_t<0> >
class CsvWriter
{
public:
typedef typename mpl_::at<Sequence,pos>::type current_type;
typedef typename boost::call_traits<current_type>::param_type param_type;
CsvWriter(std::ostream& out): mOut(out) {}
typename result_of::operator_in<Sequence,pos>::type
operator<<(param_type item)
{
typedef typename result_of::operator_in<Sequence,pos>::type result_type;
if (pos::value != 0) mOut << ',';
mOut << item;
if (result_type::is_last_type::value) mOut << std::endl;
return result_type(mOut);
}
private:
std::ostream& mOut;
}; // class CsvWriter
/// Lil' bit of black magic
namespace result_of { // thanks Boost for the tip ;)
template <class Sequence, class pos>
struct operator_in
{
typedef typename boost::same_type<
typename mpl_::size<Sequence>::type,
typename mpl_::next<pos>::type
> is_last_type;
typedef typename mpl_::if_<
is_last_type,
CsvWriter< Sequence, mpl_::size_t<0> >,
CsvWriter< Sequence, typename mpl_::next<pos>::type >
>::type;
}; // struct operator_in<Sequence,pos>
} // namespace result_of
这里有一个流编写器,可确保 cvs 文件格式正确...在字符串中显示换行符;)