Можно ли создать класс C ++, который имитирует синтаксис std :: cout, объединяя перегруженные операторы вставки так же, как это делает easylogging ++?

Код easylogging ++ определяет макрос, который делает его очень простым в использовании:

LOG(logLevel) << "This mimics std::cout syntax.  " << 1 << " + " << 1 << " = " << 2;

Я хочу сделать класс-оболочку для easylogging ++. Я могу легко создать функцию с двумя параметрами, чтобы обернуть вышеупомянутую строку. Однако возможно ли имитировать этот синтаксис в классе-обертке? Например:

Logger logger;
logger(logLevel) << "Line " << 1 << " of log text.";

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

ОБНОВИТЬ:

Благодаря ответу Starl1ght я смог заставить это работать. Я подумал, что поделюсь, если у кого-то еще будет такая же необходимость.

Я создал две перегрузки. Один был для (), а другой для <<,

Logger &operator()(logLevelT logLevel) {
mLogLevel = logLevel;
return *this;
}template <typename T>
Logger &operator<<(T const &value) {
LOG(mLogLevel) << value;
return *this;
}

ОБНОВЛЕНИЕ 2:

Я хотел обновить это сообщение снова, чтобы высказать свое мнение и показать свое окончательное решение.

Я рассуждаю так: мой проект — это демонстрация абстракции. Я пытаюсь продемонстрировать, что библиотеки журналов (и многое другое) могут быть абстрагированы от основной функциональности вашего программного обеспечения. Это также делает программные компоненты модульными. Таким образом, я могу поменять библиотеку easylogging ++ без потери синтаксиса, поскольку она реализована в интерфейсе модуля.

В моем последнем обновлении не упоминалось, как я преодолел препятствие цепочки вставки, поэтому я хотел опубликовать пример, чтобы показать, как я это сделал. Следующий код является упрощенным примером того, как добиться синтаксиса, подобного std :: cout для класса.

#include <iostream>         // For cout
#include <string>           // For strings
#include <sstream>          // For ostringstreamenum logLevelT {
INFO_LEVEL,
WARNING_LEVEL,
ERROR_LEVEL,
FATAL_LEVEL
};class Logger {
private:
std::string logName;

public:
Logger(std::string nameOfLog, std::string pathToLogFile) {
logName = nameOfLog;

//TODO Configure your logging library and instantiate
//     an instance if applicable.
}~Logger(){}// LogInputStream is instantiated as a temporary object.  It is used
//  to build the log entry stream.  It writes the completed stream
//  in the destructor as the object goes out of scope automatically.
struct LogInputStream {
LogInputStream(logLevelT logLevel, std::string nameOfLog) {
currentLogLevel = logLevel;
currentLogName = nameOfLog;
}// Copy Constructor
LogInputStream(LogInputStream &lis) {
currentLogLevel = lis.currentLogLevel;
currentLogName = lis.currentLogName;
logEntryStream.str(lis.logEntryStream.str());
}// Destructor that writes the log entry stream to the log as the
//  LogInputStream object goes out of scope.
~LogInputStream() {
std::cout << "Logger: " << currentLogName
<< "   Level: " << currentLogLevel
<< "   logEntryStream = " << logEntryStream.str()
<< std::endl;

//TODO Make a log call to your logging library.  You have your log level
//     and a completed log entry stream.
}// Overloaded insertion operator that adds the given parameter
//  to the log entry stream.
template <typename T>
LogInputStream &operator<<(T const &value) {
logEntryStream << value;
return *this;
}std::string currentLogName;
logLevelT currentLogLevel;
std::ostringstream logEntryStream;
};// Overloaded function call operator for providing the log level
Logger::LogInputStream operator()(logLevelT logLevel) {
LogInputStream logInputStream(logLevel, logName);

return logInputStream;
}// Overloaded insertion operator that is used if the overloaded
//  function call operator is not used.
template <typename T>
Logger::LogInputStream operator<<(T const &value) {
LogInputStream logInputStream(INFO_LEVEL, logName);

logInputStream << value;

return logInputStream;
}
};int main(int argc, char *argv[]) {

Logger logger1 = Logger("Logger1", "/path/to/log.log");
Logger logger2 = Logger("Logger2", "/path/to/log.log");

logger1(INFO_LEVEL) << "This is the " << 1 << "st test";

logger2(ERROR_LEVEL) << "This is the " << 2 << "nd test";

logger2 << "This is the " << 3 << "rd test";

return 0;
}

Я чувствую, что мог бы лучше справиться с именами и комментариями, но мне не хватает времени. Я определенно открыт для любых комментариев или критики.

3

Решение

Вы должны перегрузить operator() Итак, он установит внутренний уровень журнала и вернет *this как тип Logger&перегружен operator<< будет работать с возвращенной ссылкой с необходимым набором лог-уровня.

Что-то вроде этого:

Logger& Logger::operator()(LogLevel level) {
// set internal log level
return *this;
}
3

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

Других решений пока нет …

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