Изменить класс журнала, чтобы принимать переменные в строке - C ++ - PullRequest
1 голос
/ 27 июля 2011

Я пытаюсь изменить мой класс журнала, чтобы принимать переменные в моей строке.Например, если я хочу вывести, что в области 7 игроков.

Вот моя функция записи в журнал:

void Log::writeSuccess(string text,...)
{
    // Write the sucessfull operation to the logfile
    logfile << "<---> " << text << endl;
}

А вот мой код вызова:

int playernum = 7;

errorLog.writeSuccess("There are %i players in the area", playernum);

Это просто заканчивается выводом в файл: в области есть% i игроков

Есть ли способ это исправить?

Ответы [ 5 ]

6 голосов
/ 27 июля 2011

Интересно, как вообще ваша программа компилируется ?!Вы вызываете writeSuccess с 2 аргументами, в то время как объявлено, что он принимает только один аргумент.

Вам следует взглянуть на boost format

2 голосов
/ 28 июля 2011

Проблема с использованием строк в стиле printf в том, что эти строки

  1. в зависимости от типов предоставленных аргументов и
  2. зависит от порядка предоставленных аргументов.

Это не только подвержен ошибкам , когда вы пишете эти строки. По моему опыту, типы и порядок аргументов легко изменятся в программном обеспечении, которое активно поддерживается и расширяется, и гораздо сложнее поддерживать синхронизацию строк формата с изменениями, примененными позже, чем при первоначальной записи код.

Проблема необходимости вручную поддерживать синхронизацию типов параметров со строкой форматирования может быть легко решена в C ++, streams доказали это 25 лет назад. Boost.Format даже удается объединить строки форматирования с типом безопасности.

Некоторые библиотеки журналов используют другой подход, решающий обе проблемы: они используют синтаксис, в котором вы указываете, какой параметр должен быть вставлен в определенное место в строке, с помощью имя параметра , и они освобождают вас от необходимости думать о типе параметра путем индивидуального преобразования всех параметров в строки перед их вставкой:

log( "i now has the value of @(i), current size is @(x.get_size(y))", 
     LOG_PARAM(i) + LOG_PARAM(x.get_size(y)) );
1 голос
/ 08 сентября 2012

Если вы не хотите использовать stdarg.h, который плохо выглядит в c ++ IMO.Вы можете сделать что-то вроде этого.Имейте в виду, что, хотя это небольшой класс (вы можете добавить к нему для лучшей регистрации), это не самый эффективный способ сделать это.

#include <iostream>
#include <sstream>


class Log
{
public:
    Log() : os()
    {

    }

    ~Log()
    {
        fprintf(stderr, "%s\n", os.str().c_str());
    }

    template<typename T>
    std::ostringstream &operator<<(const T &t)
    {
        os << "Log file - " << t;
        return os;
    }

private:
    std::ostringstream os;
};

int main(int argc, char *argv[])
{
    //usage
    for (int i = 0; i < 10; ++i)
        Log() << "Hello world " << i;

    return 0;
}
0 голосов
/ 27 июля 2011

Если вы не можете или не хотите использовать повышение:

void Log::writeSuccess(const char* const fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    char buff[1024];
    vsnprintf(buff, sizeof(buff), fmt, ap);
    logfile << buff;
}

Примечание: предполагается, что длина записи ограничена.

Обновление: с помощью gcc это можно сделать безопасным для типов способом, вам нужно следующее объявление:

class Log {
    void writeSuccess(const char* const fmt, ...) __attribute__ ((format (printf, 2, 3)));
    //...
};

Info здесь .Примечание: это предупреждение, а не ошибка компиляции.Если вы игнорируете предупреждения, это ваша проблема ..:)

0 голосов
/ 27 июля 2011

Посмотрите на стандартную библиотеку .Позволяет обрабатывать переменное количество параметров.

...