Как использовать мой класс ведения журнала, например, 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.