Пользовательский поток для метода в C ++? - PullRequest
3 голосов
/ 06 декабря 2010

Я делаю регистратор и хочу, чтобы происходили какие-то потоковые события, в идеале - CLogger << "Testing, " << 1 << ",2,3\n"; вместо CLogger->log("Testing, %i,2,3", 1);

Мой вопрос: как мне это сделать?Я не хочу напрямую создавать поток для stdout, так как я хочу использовать свой собственный метод, который включает в себя запись файлов и тому подобное.Я рассмотрел перегрузку с определенной структурой, которая сбрасывает текущий поток буфера в метод, но я должен был бы сделать CLogger << flush << "Test!\n";, что немного странно.

Кто-нибудь знает, как это сделать

Ответы [ 5 ]

13 голосов
/ 07 декабря 2010

Если все, что вам нужно, это направить определенные сообщения журнала в файлы, вы рассмотрели std::ofstream?

В противном случае, мне нравится выводить класс журналирования из std::ostream, поэтому я получаю все качества потока. Хитрость заключается в том, чтобы поместить весь код для вашего приложения в соответствующий класс streambuf. Рассмотрим:

#include <iostream>
#include <sstream>

class CLogger : public std::ostream {
private:
    class CLogBuf : public std::stringbuf {
    private:
        // or whatever you need for your application
        std::string m_marker;
    public:
        CLogBuf(const std::string& marker) : m_marker(marker) { }
        ~CLogBuf() {  pubsync(); }
        int sync() {
            std::cout << m_marker << ": " << str();
            str("");
            return std::cout?0:-1;
        }

    };

public:
    // Other constructors could specify filename, etc
    // just remember to pass whatever you need to CLogBuf
    CLogger(const std::string& marker) : std::ostream(new CLogBuf(marker)) {}
    ~CLogger() { delete rdbuf(); }
};

int main()
{
    CLogger hi("hello");
    CLogger bye("goodbye");

    hi << "hello, world" << std::endl;
    hi << "Oops, forgot to flush.\n";
    bye << "goodbye, cruel world\n" << std::flush;
    bye << "Cough, cough.\n";
}

Примечания:

  • Конструктор CLogger может принимать любые параметры, которые вам нужно использовать - имя файла, язык вывода, указатель на базовые данные журнала, что угодно. Просто передайте данные в класс CLogBuf. * ​​1011 *
  • sync () CLogBuf автоматически вызывается во время ответа на std :: flush.
6 голосов
/ 06 декабря 2010

Проверьте operator <<, что является перегрузкой потоков STL.

class CLogger
{
public:
    CLogger& operator << (const std::string& _rhs)
    {
        // work with it here
        return *this;
    }; // eo operator <<
}; // eo class CLogger

EDIT:

На этой странице показано, как перегрузки std :: ostream operator << для разных типов:

http://www.cplusplus.com/reference/iostream/ostream/operator%3C%3C/

2 голосов
/ 06 декабря 2010

Реализация прокси-объекта, который предоставляет вам оператор << и передает маркер владения возвращенному прокси-объекту. Когда объект с маркером владения умирает, вы очищаете поток. </p>

Простой способ сделать это - заключить ostringstream в auto_ptr в вашем прокси и сбросить в журнал, когда auto_ptr не равен нулю в d-tor прокси.

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

Подумайте о чем-то вроде этого:

class CLoggingProxy
{
public:
  template <class T>
  CLoggingProxy operator<<( const T& rhs )
  {
    if ( stream )
      *stream << rhs;
    return *this;
  }

  ~CLoggingProxy()
  {
    if ( stream )
      logger->log(stream->str());
  }

private:
  std::auto_ptr<std::ostringstream> stream; 
  CLogger* logger;

  friend class CLogger;
  CLoggingProxy( CLogger* logger ) // call this e.g. from the logger to "start" input
  : stream(new std::ostringstream), logger(logger) {}
};
1 голос
/ 06 декабря 2010

Все функции operator<<() определены в классе ostream, от которого вы можете наследовать и реализовывать его методы.

0 голосов
/ 06 декабря 2010

Я просто собираюсь скопировать и вставить мою текущую реализацию этого ниже, она делает все, что вам нужно (и обрабатывает такие вещи, как std::endl и тому подобное). AMBROSIA_DEBUG - это макрос, определенный в отладочных сборках, поэтому в теории каждый вызов этого выходного класса должен быть опущен в сборках выпуска (хотя не проверено, но кажется, что логические издержки сведены к минимуму. Функциональность основана на QDebug функциональность, плюс небольшое добавление моего debugLevel, которое позволит вам вручную отфильтровывать отладочные сообщения в вашем коде в зависимости от параметра времени выполнения. Сейчас он также добавляет одинаковое количество пробелов перед каждым сообщением.

// C++ includes
#include <iostream>
#include <string>

typedef std::ostream& (*STRFUNC)(std::ostream&);

#ifdef AMBROSIA_DEBUG
    static int debugLevel;
    const static int maxDebugLevel = 9;
#endif

class Debug
{
public:

    #ifdef AMBROSIA_DEBUG
    Debug( const int level = 0 )
    : m_output( level <= debugLevel ),
      m_outputSpaces( true ),
      m_spaces( std::string(level, ' ') )
    #else
    Debug( const int )
    #endif // AMBROSIA_DEBUG
    {}

    template<typename T>
    #ifdef AMBROSIA_DEBUG
    Debug& operator<<( const T &output )
    {
        if( m_output )
        {
            if( m_outputSpaces )
            {
                m_outputSpaces = false;
                std::cerr << m_spaces;
            }
            std::cerr << output;
        }
    #else
    Debug& operator<<( const T & )
    {
    #endif // AMBROSIA_DEBUG
        return *this;
    }
    // for std::endl and other manipulators
    typedef std::ostream& (*STRFUNC)(std::ostream&);
    #ifdef AMBROSIA_DEBUG
    Debug& operator<<( STRFUNC func )
    {
        if( m_output )
            func(std::cerr);
    #else
    Debug& operator<<( STRFUNC )
    {
    #endif // AMBROSIA_DEBUG
        return *this;
    }
private:
#ifdef AMBROSIA_DEBUG
    bool m_output;
    bool m_outputSpaces;
    std::string m_spaces;
#endif // AMBROSIA_DEBUG
};

Пример использования:

int main()
{
    debugLevel = 9; // highest allowed in my app...
    Debug(4) << "This message should have an indentation of 4 spaces." << endl;
    Debug(8) << "This is a level 8 debug message.\n";
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...