Как использовать мой класс ведения журнала, например, std-поток С++?

У меня есть рабочий класс logger, который выводит некоторый текст в richtextbox (Win32, С++). Проблема в том, что я всегда использую ее так:

stringstream ss;  
ss << someInt << someString;  
debugLogger.log(ss.str());

вместо этого было бы гораздо удобнее использовать его, как поток, как в:

debugLogger << someInt << someString;

Есть ли лучший способ, чем пересылка всего на внутренний экземпляр stringstream? Если бы это было сделано, когда мне нужно было сфотографироваться?

Ответ 1

Вам необходимо реализовать operator << для вашего класса. Общий шаблон выглядит следующим образом:

template <typename T>
logger& operator <<(logger& log, T const& value) {
    log.your_stringstream << value;
    return log;
}

Обратите внимание, что это касается ссылок (не const), поскольку операция изменяет ваш регистратор. Также обратите внимание, что вам нужно вернуть параметр log для того, чтобы цепочки работала:

log << 1 << 2 << endl;
// is the same as:
((log << 1) << 2) << endl;

Если самая внутренняя операция не вернула текущий экземпляр log, все остальные операции либо завершились с ошибкой во время компиляции (неправильная подпись метода), либо будут проглатываться во время выполнения.

Ответ 2

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

Путь к тому, чтобы определить свой собственный streambuf и связать его с потоком. Затем вам просто нужно использовать поток.

Вот несколько простых примеров:

Ответ 3

В классе Logger переопределите < Оператор.

Нажмите Здесь, чтобы узнать, как реализовать < < Оператор.

Вы также можете избежать операторов ведения журнала внутри кода используя аспектно ориентированное программирование.

Ответ 4

Как отметил Люк Хермит , есть "Logging In С++" который описывает очень аккуратный подход к решению этой проблемы. В двух словах, если у вас есть такая функция, как:

void LogFunction(const std::string& str) {
    // write to socket, file, console, e.t.c
    std::cout << str << std::endl;
}

можно написать оболочку, чтобы использовать ее в std:: cout как:

#include <sstream>
#include <functional>

#define LOG(loggingFuntion) \
    Log(loggingFuntion).GetStream()

class Log {
    using LogFunctionType = std::function<void(const std::string&)>;

public:
    explicit Log(LogFunctionType logFunction) : m_logFunction(std::move(logFunction)) { }
    std::ostringstream& GetStream() { return m_stringStream; }
    ~Log() { m_logFunction(m_stringStream.str()); }

private:
    std::ostringstream m_stringStream;
    LogFunctionType m_logFunction;
};

int main() {
    LOG(LogFunction) << "some string " << 5 << " smth";
}

(онлайн-демонстрация)

Кроме того, есть очень приятное решение, предоставленное Stewart.