Библиотека boost::format предоставляет удобный и безопасный(по сравнению с printf) способ форматирования строк. Возможен как классический printf-стиль:
cout << format("writing %s, x=%s : %d-th step \n") % "toto" % 40.23 % 50;
Так и другие, более гибкие способы форматирования, как, например, такой:
cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // 'simple' style.
Самая очевидная проблема с printf — это то, что мы должны точно указать размер каждого аргумента. Например, для
time_t в одних случаях писать
%I64d, а в других
%d. У
time_t разный размер может быть и на 32-х битной платформе в зависимости от компилятора. И это только один пример. С boost::format такие проблемы исключаются.
Подробнее по всем возможностям можно посмотреть в
документации. Но речь сейчас не о возможностях boost::format , а о том как их применить у себя в программе. Мне кажется, что очень удобно было бы, например, писать информацию в лог файл без предварительного форматирования строки на стеке. Т.е. писать вместо:
string msg = str( boost::format("Debug message %s") % some_msg_string );
log( msg );
вот такую строку:
log("Debug message %s") % some_msg_string;
Добиться этого не сложно. Нужно, всего лишь, перегрузить оператор %. Для этого создадим класс
formatted_log_t. А ещё функцию
log, которая возвращает экземпляр этого класса. Класс будет содержать в себе экземпляр boost::format.
#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;
class formatted_log_t {
public:
formatted_log_t(const wchar_t* msg ) : fmt(msg) {}
~formatted_log_t() { wcout << fmt << endl; }
template <typename T>
formatted_log_t& operator %(T value) {
fmt % value;
return *this;
}
protected:
boost::wformat fmt;
};
Оператор % должен быть шаблонным так как мы не знаем типы форматируемых аргументов. Функция
log будет иметь следующий вид:
formatted_log_t log(const wchar_t* msg)
{
return formatted_log_t( msg );
}
На этом месте реализация функции уже является вполне работоспособной. Далее можно добавлять какие-то другие фичи. Например, фильтр по уровню сообщений. Для этого сделаем функцию и класс шаблонными. Вот так:
#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;
enum log_level_t {
LOG_NOTHING,
LOG_CRITICAL,
LOG_ERROR,
LOG_WARNING,
LOG_INFO,
LOG_DEBUG
};
template<int level>
class formatted_log_t {
public:
formatted_log_t(const wchar_t* msg ) : fmt(msg) {}
~formatted_log_t() {
// GLOBAL_LEVEL is a global variable and could be changed at runtime
if ( level <= GLOBAL_LEVEL ) wcout << fmt << endl;
}
template <typename T>
formatted_log_t& operator %(T value) {
fmt % value;
return *this;
}
protected:
boost::wformat fmt;
};
template <int level>
formatted_log_t<level> log(const wchar_t* msg)
{
return formatted_log_t<level>( msg );
}
Применять этот код можно так:
int main ()
{
log<LOG_DEBUG>(L"TEST %3% %2% %1%") % 5 % 10 % L"privet";
return 0;
}
Работа с логом, наверное, самое очевидно, но только одно из возможных применений синтаксиса boost::format и далее можно развивать эту идею как вам больше нравится.