browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

复用 ostream 实现日志类

Posted by on 2013 年 05 月 10 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

Bjarne 老爷子教导我们:要忘记 stdio.h,改用 iostream。于是,有了我这个日志类。主要站在了 ostream 的肩膀上,所以代码并不多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <atlbase.h>
#include <sstream>
#include <string>
 
class DebugBuffer : public std::stringbuf
{
protected:
    virtual int sync(void)
    {
        std::string dbg = str();
        if (!dbg.empty()) {
            ::OutputDebugStringA(dbg.c_str());
            dbg.clear();
            str(dbg);
        }
        return 0;
    }
};
 
class Logger : public std::basic_ostream<char>
{
public:
    Logger(void) : std::basic_ostream<char>(&m_buf)
    {
        // Nothing
    }
protected:
    DebugBuffer m_buf;
};

示例:

1
2
Logger logger;
logger << "Hello, World!" << endl;

考虑到 Logger 是对 basic_ostream<char> 的继承,而有时又需要输出宽字符串,所以可以增加一个 operator << 的实现:

1
2
3
4
5
6
7
8
inline std::basic_ostream<char>& operator << (std::basic_ostream<char>& stm,
    const std::wstring& ws)
{
    USES_CONVERSION;
    std::string str(W2CA(ws.c_str()));
    stm << str;
    return stm;
}

当然,大多数时候我们希望只在 Debug 配置时输出日志。那么可以这么修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifdef _DEBUG
 
#define DBGLOG(x)  x
#define LogEndl    (std::endl)
 
#else
 
class EmptyLogger
{
};
 
extern __declspec(selectany) EmptyLogger theEmptyLoger;
 
template <typename T>
inline EmptyLogger& operator<<(EmptyLogger& logger, const T& obj)
{
    return logger;
}
 
#define DBGLOG(x)   theEmptyLoger
#define LogEndl     0
 
#endif

示例:

DBGLOG(logger) << "Hello, World!" << LogEndl;

什么?还是钟情于类 printf 的格式控制符?也没问题,再加一个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Formatter
{
public:
    explicit Formatter(const char *format, ...)
    {
        va_list args;
        va_start(args, format);
        size_t len = _vscprintf(format, args);
        m_str.resize(len);
        vsprintf_s(const_cast<char *>(m_str.c_str()), len + 1, format, args);
        va_end(args);
    }
private:
    friend std::basic_ostream<char>& operator << (std::basic_ostream<char>&,
        const Formatter&);
    std::string m_str;
};
 
inline std::basic_ostream<char>& operator << (std::basic_ostream<char>& stm,
    const Formatter& fmt)
{
    stm << fmt.m_str;
    return stm;
}

示例:

DBGLOG(logger) << Formatter("%x", 123) << LogEndl;

订阅本站

一条评论

  • At 2013.05.10 23:18, antkillerfarm said:

    C++不用已经好多年了。。。好在用的语法还不复杂,勉强看懂

    (Required)
    (Required, will not be published)