Как написать класс журнала с интерфейсом в стиле cout (logger << "Ошибка:" << val << endl;) - PullRequest
6 голосов
/ 10 февраля 2010

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

Logger log;
log << "Error: " << value << "seen" << endl;

Это должно напечатать мне отформатированное сообщение. Например. "12-09-2009 11:22:33 Ошибка 5 замечена"

Мой простой класс в настоящее время выглядит так:

class Logger {
    private:
        ostringstream oss;
    public:
        template <typename T>
        Logger& operator<<(T a);
}

template <typename T>
Logger& Logger::operator<<(T a) {
    oss << a;
    return *this;
}

void functionTest(void) {
    Logger log;
    log << "Error: " << 5 << " seen";
}

Это заставит oss правильно иметь буфер "Ошибка: 5 замечено". Но я не знаю, какую еще функцию мне нужно написать / изменить, чтобы что-то печаталось на экране. Кто-нибудь знает, как заставить это работать или есть другой способ создать этот класс, чтобы мои функциональные возможности работали?

Ответы [ 5 ]

4 голосов
/ 10 февраля 2010

За каждым std::ostream стоит streambuf. Его можно получить и установить с помощью std::stream::rdbuf(). В частности, его можно обернуть - вы можете предоставить объект streambuf, который постобрабатывает потоковый текст. ( постобработка означает, что вы не можете отличить std::cout << 123; от std::cout << "123";)

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

1 голос
/ 23 января 2015

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

Даже если деструктор будет использоваться как EOL / Flush,

{ log << [anything]; } как синтаксис скобок inline-local stack для вызова деструктора журнала, выходящего из скобок, или как std :: endl, либо должны использоваться либо.

Если мета-объект не реализован с помощью некоторого оператора присоединения, такого как «<<» или «+», вы заканчиваете весь путь, обязанный использовать явный способ завершить строку и / или очистить. </p>

1 голос
/ 06 февраля 2013

Проверьте простой регистратор, предложенный в Оптимизация времени компиляции - удаление отладочных отпечатков из двоичных файлов выпуска . Должно быть достаточно для ваших нужд. Br, Gracjan

1 голос
/ 10 февраля 2010

Насколько я вижу, ваш логгер ничем не отличается от ostringstream. Он просто берет то, что дано, и выводит его в поток строк. Если вы хотите использовать его таким образом, вы можете написать деструктор для Logger, который выводит строку в cout.

Logger::~Logger()
{
    std::cout<<getcurrentDateTimeAsString()<<" "<<oss.str()<<std::endl;
}

Но, конечно, это не имеет смысла, если Logger * создается и используется в программе.

0 голосов
/ 10 февраля 2010

Это (из этого сообщения ) делает то, что вы хотите, но оно заставляет вас заканчивать каждую строку std :: endl:

class Logger {
    private:
        ostringstream oss;
    public:
        template <typename T>
        Logger& operator<<(T a);

    Logger& operator<<( std::ostream&(*f)(std::ostream&) )
    {
        if( f == std::endl )
        {
            std::cout << "12-09-2009 11:22:33" << oss.str() << std::endl;   
            oss.str("");
        }
        return *this;
    }
};

template <typename T>
Logger& Logger::operator<<(T a) {
    oss << a;
    return *this;
}

void functionTest(void) {
    Logger log;
    log << "Error: " << 5 << " seen" << std::endl;
}

int main()
{
    functionTest();
}

РЕДАКТИРОВАТЬ: Ну, согласно вашему комментарию, это не то, что вы хотите. Тогда я рекомендую вам сделать, как говорят MSalters.

...