C++ 中的自定义流到方法?

发布于 2024-10-06 03:09:06 字数 309 浏览 5 评论 0原文

我正在制作一个记录器,我希望发生某种类似流的事件,最好是 CLogger << “测试”<< 1<<; ",2,3\n"; 而不是 CLogger->log("Testing, %i,2,3", 1);

我的问题是我该怎么做?我不想直接创建到标准输出的流,因为我想使用我自己的方法,其中包括写入文件等。我考虑过使用某个结构进行重载,将当前流缓冲区刷新到方法,但我必须执行 CLogger <<冲洗<< “测试!\n”; 这有点奇怪。

有人知道该怎么做吗?

I'm making a logger and I wish to have some kind of stream-like happenings going on, ideally doing CLogger << "Testing, " << 1 << ",2,3\n"; instead of CLogger->log("Testing, %i,2,3", 1);

My question is how would I do this? I don't want to directly create a stream to stdout as I want to use my own method which includes writing files and such. I've considered overloading with a certain struct that'd flush the current stream buffer to a method, but I'd have to do CLogger << flush << "Test!\n"; which is kind of odd.

Does anybody know how to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

离去的眼神 2024-10-13 03:09:06

如果您需要的只是将某些日志消息定向到文件,您是否考虑过 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 类即可。
  • CLogBuf 的sync() 在响应std::flush 期间自动调用。

If all that you need is directing certain log messages to files, have you considered std::ofstream?

Otherwise, I like to derive my logging class from std::ostream, so I get all of the stream goodness. The trick is to put all of your application-specific code in the associated streambuf class. Consider:

#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";
}

Notes:

  • The CLogger constructor can take whatever parameters you need to use -- a filename, an output language, a pointer to the underlying log data, whatever. Just pass the data onto the CLogBuf class.
  • The CLogBuf's sync() is automatically called during in response to std::flush.
别再吹冷风 2024-10-13 03:09:06

查看运算符<<,它是STL 的流重载的内容。

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

编辑:

请参阅此页面,概述了 std::ostream 如何重载不同类型的运算符 <<:

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

Check out operator <<, which is what STL's streams overload.

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

EDIT:

See this page that outlines how std::ostream overloads operator << for different types:

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

铁憨憨 2024-10-13 03:09:06

实现一个代理对象,为您提供运算符<<并将所有权标记传递给返回的代理对象。当带有所有权标记的对象死亡时,您将刷新流。

执行此操作的一个简单方法是将 ostringstream 包装在代理中的 auto_ptr 中,并在代理的 d-tor 中 auto_ptr 不为 null 时刷新到记录器。

这将为您提供 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) {}
};

Implement a proxy object that gives you operator<< and pass an ownership marker to the returned proxy object. When an object with the ownership marker dies, you flush the stream.

An easy way to do this would be to wrap ostringstream in an auto_ptr in your proxy and flushing to your logger when the auto_ptr is not null in the proxy's d-tor.

That'll give you the formatting possible with ostream, but still result in only one call to your logger, which I thought was the real problem.

Think of something like this:

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) {}
};
那一片橙海, 2024-10-13 03:09:06

所有 operator<<() 函数都在类 ostream 上定义,您可以继承该类并实现其方法。

All of the operator<<() functions are defined on the class ostream, which you can inherit from and implement its methods.

暖伴 2024-10-13 03:09:06

我将在下面复制粘贴我当前的实现,它可以满足您所需的一切(并处理诸如 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;
}

I'm just going to copy-paste my current implementation of this below, it does all you need (and handles things like std::endl and the like). AMBROSIA_DEBUGis macro defined in debug builds, so in theory, every call to this output class should be omitted in release builds (haven't checked though, but seems logical overhead is kept to a minimum. The functionality is based on QDebug functionality, plus a little addition of mine debugLevel, which would allow you to filter debug messages by hand in your code depending on a runtime parameter. Right now it also adds the same amount of spaces before each message.

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

Example usage:

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文