Здесь есть 2 вопроса.
Один имеет дело с потоковыми манипуляторами, следуйте цитате.
Другой имеет дело с проблемами форматирования.
Форматирование сложно, особенно то, как вы его указываете, потому что оно предполагает возможность анализа формата и генерации AST-представления, которое затем будет вызываться для фактического форматирования строки. Разбор означает, что вам нужно определить небольшую грамматику и т. Д. *
Существуют библиотеки, такие как Boost.Spirit, которые занимаются синтаксическим анализом / генерацией, и они намного сложнее, чем «простой» Boost.Format (который сам по себе не так прост).
Теперь, вы могли бы отказаться от анализа?
class Date
{
public:
Date(year_t year, month_t month, day_t day);
year_t getYear() const;
month_t getMonth() const;
day_t getDay() const;
private:
year_t mYear;
month_t mMonth;
day_t mDay;
};
Преимущество этого класса несколько:
- Структурированная информация: анализирует один, читает столько, сколько вы хотите
- Проверка: вычеркнуть недопустимую дату (29 февраля 2010?)
- Нет двусмысленности: действительно ли «100102» - это «1 февраля 2010» или «2 января 2010»? (хотя бы не разобрано)
Затем вы можете сделать то же самое для формата, создав небольшой механизм форматирования.
template <class T>
class Formatter
{
public:
virtual ~Formatter() {}
virtual Formatter* clone() const = 0;
virtual std::string evaluate(const T& item) const = 0;
};
template <class T>
class FormatterConstant: public Formatter
{
public:
explicit FormatterConstant(const std::string& s): mValue(s) {}
virtual Formatter<T>* clone() const { return new FormatterConstant(*this); }
virtual std::string evaluate(const T&) const { return mValue; }
private:
std::string mValue;
};
template <class T>
class FormatterComposite: public Formatter<T>
{
typedef std::vector< const Formatter<T>* > formatters_type;
typedef typename formatters_type::const_iterator const_iterator;
public:
// Need suitable Copy and Assignment Constructors
~FormatterComposite()
{
for(const_iterator it = mFormatters.begin(), end = mFormatters.end();
it != end; ++it) delete *it;
}
virtual Formatter<T>* clone() const { return new FormatterComposite(*this); }
virtual std::string evaluate(const T& item) const
{
std::string result;
for(const_iterator it = mFormatters.begin(), end = mFormatters.end();
it != end; ++it) result += (*it)->evaluate();
return result;
}
void imbue(std::ostream& s) { mStream = &s; }
FormatterComposite& operator<<(const std::string& s)
{
mFormatters.push_back(new FormatterConstant<T>(s); }
return *this;
}
FormatterComposite& operator<<(const Formatter<T>& formatter)
{
mFormatters.push_back(formatter.clone());
return *this;
}
std::ostream& operator<<(const T& item) const
{
return (*mStream) << this->evaluate(item);
}
private:
std::ostream* mStream;
formatters_type mFormatters;
};
template <class T>
FormatterComposite& operator<<(std::ostream& s, FormatterComposite& c)
{
c.imbue(s);
return c;
}
// Usage
class DateOfYear: public Formatter<Date>
{
public:
Formatter<Date>* clone() const { return new DateOfYear(*this); }
std::string evaluate(const Date& d) const { return toString(d.getYear()); }
};
extern const DateOfYear year;
int main(int argc, char* argv[])
{
FormatterComposite<Date> formatter;
Date date;
std::cout << formatter << "Date is 20"
<< year << "/" << month << "/" << day << date;
return 0;
}
Здесь вы отказываетесь от разбора. Конечно, это означает, что формат жестко закодирован ...