передача параметров — удобный оператор ведения журнала для C ++ с использованием boost :: format

Я хочу разработать функцию регистрации со следующими характеристиками:

  • основанный на std :: string, а не char *
  • поддерживает переменное количество переменных, таких как printf
  • принимает в качестве первого параметра уровень серьезности
  • избегает форматирования, когда уровень серьезности ниже уровня регистрации
  • так же просто, как printf, или почти

Я склонен использовать boost :: format из-за его автоматического преобразования типов. Но вот некоторые проблемы, которые я вижу:

Его синтаксис немного неловкий: format("Mgr %s on pid %d is in state %s" % mgr % pid % s) это немного сложно для глаз (характер переменных не так очевиден без запятых). Вызов журнала будет выглядеть так:

mylog(INFO, format("Mgr %s on pid %d is in state %s" % mgr % pid % s));

Что еще хуже, возможно ли даже реализовать mylog (), чтобы проверить, регистрируем ли мы сообщения INFO до объект формата построен?

Другой подход, о котором я подумал, который выглядит ближе к printf, был бы

mylog(INFO, "Mgr %s on pid %d is in state %s", mgr, pid, s);

или даже

mylog_info("Mgr %s on pid %d is in state %s", mgr, pid, s);

Реализация будет что-то вроде:

mylog(int severity, string pattern, ...) {
if (severity >= LOGLEVEL) {
boost::format fmt(pattern);
for parm /* remaining parameters */ {
fmt % parm; // feed into format one at a time
}
}
}

Это, безусловно, откладывает строительство формат объект, пока он не нужен. Но из того, что я могу сказать, при обходе списка переменных аргументов невозможно определить, когда вы достигли конца!

Может кто-нибудь предложить синтаксически простую технику выполнения этого?

Примечание: у меня есть g ++ 4.4, который не поддерживает все c ++ 11 (хотя он поддерживает шаблоны с переменным числом аргументов)

1

Решение

Вы можете использовать вариационные шаблоны и рекурсию.

Замечания: Поскольку вы упоминаете GCC 4.4, эта функция доступна для этого компилятора, но он не включен по умолчанию. Вы должны добавить либо -std=c++0x или же -std=gnu++0x опция для компилятора, чтобы включить функцию.

Решение может быть реализовано как что-то вроде этого:

// Does the actual logging of the formatted message
void mylog_r (int severity, boost::format &fmt) {
std::cout << "[" << severity << "] "<< fmt
<< std::endl;
}

// Unpacks the variadic arguments one at a time recursively
template <typename T, typename... Params>
void mylog_r (int severity, boost::format &fmt, T arg, Params... parameters) {
mylog_r(severity, fmt % arg, parameters...); // recursively unpack
}

// This version of mylog() checks severity and converts fmt to boost::format
template <typename... Params>
void mylog (int severity, std::string fmt, Params... parameters) {
if (severity < LEVEL) return;
boost::format bfmt(fmt);
mylog_r(severity, bfmt, parameters...);
}
1

Другие решения

Вы можете сделать что-то подобное, например, реализацию printf:

#include <stdio.h>
#include <stdarg.h>
#include <string>

using namespace std;

enum Info_t
{
NONE,
WARNING,
ERROR   // so on
};

int myLog(Info_t severity, string format, ...)
{
int done = 0;
if ( severity > WARNING ) {
va_list arg;

va_start(arg, format.c_str());
done = vfprintf(stdout, format.c_str(), arg);
va_end(arg);
}

return done;
}

int main()
{
myLog(NONE, "Print %s %d.\n", "NONE", 0);
myLog(WARNING, "Print %s %d.\n", "WARNING", 1);
myLog(ERROR, "Print %s %d.\n", "ERROR", 2);
}
0

По вопросам рекламы [email protected]