#include <iostream>
#include <sstream>
//---------------------------------------------//
// ENSURE 方式的log
//---------------------------------------------//
class CEnsureLog
{
private:
mutable std::string m_osLog;
public:
CEnsureLog(const char* func, int line, const char* logType, const char* log)
{
std::ostringstream so;
so << "[" << func << ":" << line << "]" << logType << log /*<< std::endl*/;
m_osLog = so.str();
}
~CEnsureLog()
{
if (m_osLog.empty())
return;
std::cout << m_osLog.c_str() << std::endl;
}
template<typename T>
CEnsureLog& operator << (const std::pair<const char*, T> p)
{
std::ostringstream so;
so << "[" << p.first << "=" << p.second << "]";
m_osLog += so.str();
return *this;
}
CEnsureLog& operator << (int)
{
return *this;
}
const char* write() const
{
return m_osLog.c_str();
}
};
static int A = 0, B = 0;
#define AB(a, N) std::make_pair(#a, a) << N
#define A(a) AB(a, B)
#define B(a) AB(a, A)
#define ENSURELOG(b, logType) if (b); else CEnsureLog(__FUNCTION__, __LINE__, logType, #b) << A
/*
宏解释:
例如:
ENSURELOG(false, "Info")("abc")(5);
展开式:
CEnsureLog 对象 << AB("abc", B)(5);
<< std::make_pair("abc", "abc") << B(5)
<< AB(5, A)
<< std::make_pair(5, 5) << A
后面没有了,所以A取的是 static int A = 0; 0, 调用 operator << (int)
*/
int main()
{
std::string str = "str";
int num = 11;
ENSURELOG(false, "[info]")("abc")(5)(str)(num);
return 0;
}
ENSURE是windows api 里面的函数,assert的一种扩展,没有开放到标准里面,调用的方式是 ENSURE(exp)(msg)(msg)(msg)...;这种写法很不错,我们可以很直观的写需要打印的东西,虽然跟一般C++的语法看起来不协调。
一般我们习惯使用的记录log的方式是 ("%s : %d", str, num) printf的组织方式,但是这样经常会遇到的问题是,format部分的代码很容易写错,尤其是 int64 int32这种类型的区分;当然在linux上面其实更习惯用std::cout方式,再做重定向到日志文件中去,避免代码中format的组织。
上面代码是参考网上:
参考了:http://www.cnblogs.com/cbscan/archive/2012/10/26/2740838.html 代码
去掉了try catch的内容,让ENSURELOG的宏定义只是用来打印日志,外层可以写嵌套assert的内容,或者不同种类log的宏。
主要解释了宏的展开式,当时看了好一会儿才绕明白,这里记录一下。