Хотя я могу оценить идею перегрузки потокового оператора, я бы поставил под сомнение практику для рассматриваемой проблемы.
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 ... исключая символы новой строки в строках;)