2016-11-30 1 views
3
код

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

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

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

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

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

UPDATE:

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

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

Logger &operator()(logLevelT logLevel) { 
    mLogLevel = logLevel; 
    return *this; 
} 


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

UPDATE 2:

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

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

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

#include <iostream>   // For cout 
#include <string>   // For strings 
#include <sstream>   // For ostringstream 


enum 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; 
} 

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

+0

Это уже реализовано хорошо и короткие. Вы пишете больше кода для простой причины! – ninja

ответ

3

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

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

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

Большое спасибо! Это именно то, что необходимо для его работы. – Blackwood

Смежные вопросы