停止评估操作员<<
Stop evalulate operator<<
我正试图为自己做一个简单的日志库。我知道有几个曾经,但我没有发现任何头文件,小的,非常"c++"像日志库适合我的应用程序。
目前我有以下语法:
logger << debug << "A debug message" << end; //debug and end is my custom manipulators
我已经实现了所有必要的运算符<<它工作得很好,特别是当它与std::ostream向后兼容时。但我想知道,只是为了效率,如果它是一个为什么停止评估任何东西,如果一些消息不应该被记录(在调试后的例子)?让严厉操控者之后的一切都"消失"?
现在我有以下代码:
template <typename Type>
Logger & Logger::operator<<(const Type & message)
{
if(this->get_message_level() <= this->get_severity())
{
BOOST_FOREACH(std::ostream* stream, this->_sinks)
{
*stream << message;
}
}
return *this;
}
Logger & Logger::operator<< (Logger & (*pf)(Logger&))
{
return pf(*this);
}
Logger & debug(Logger& logger)
{
logger.lock();
logger.set_severity(7);
//...
return logger;
}
Logger & end(Logger& logger)
{
logger << std::endl;
logger.unlock();
return logger;
}
你可以像
extern "C" bool want_log;
#define LOG(Arg) do { if (want_log)
cout << __FILE__ << ":" << __LINE__ ": " << Arg << endl; } while(0)
作为LOG("x=" << x)
这可能有点棘手,这取决于您愿意做出什么样的妥协在语法中接受。如果你真的想支持这一切输出到ostream
,那么你能做的最好的(到目前为止)Know)是一个包装器类,其行如下:
class Logger
{
std::ostream* myDest;
public:
// Appropriate constructors...
template<typename T>
Logger& operator<<( T const& obj )
{
if ( myDest != NULL )
(*myDest) << obj;
return *this;
}
};
如果日志记录被关闭(Logger::myDest == NULL
),则没有将执行转换代码,但您仍将计算每个参数。根据我的经验,这通常不是一个问题,因为大多数参数要么是字符串字面量,要么是一个简单的变量,但是总成本不是0。它也有潜在的缺点传播类型是而不是 std::ostream&
(尽管我从未发现)这在实践中可能是个问题)。
一个更巧妙的解决方案是使用如下行的宏:
#define logger loggerInstance != NULL && (*loggerInstance)
这仍然允许大多数实际使用相同的语法(因为&&
运算符的优先级非常低),但是在有些人太聪明了,嵌入了日志记录以更复杂的表达式输出。除了不做之外转换时,如果打开日志记录,则甚至不会计算参数了。
最后,如果你接受不同的语法,你可以这样写:
#ifndef NDEBUG
#define LOG(argList) logger << argList
#else
#define LOG(argList)
#endif
这需要用户写LOG("x = " << x)
,而不是log <<
"x = " << x
,并且需要重新编译,如果你想打开登录,但这是我所知道的唯一一个代价为0的方法
根据我的经验,大多数应用程序可以支持第一种解决方案;在一个在极少数情况下,您可能需要使用第二种;我从来没见过性能要求第三的应用程序。
请注意,即使是第一个,您也可能需要使用宏来获取记录器实例,以便自动插入__FILE__
和__LINE__
,在第二种情况下,您可能仍然希望使用包装器类,以确保析构函数中的刷新;如果应用程序是多线程的,在所有情况下都需要包装器为了使整个输出序列原子化
您可以检查Logger & Logger::operator<< (Logger & (*pf)(Logger&))
操作符的严重性,并返回一个"空"记录器,在这种情况下不打印任何内容:
class EmptyLogger : public Logger {
template <typename Type>
Logger & Logger::operator<<(const Type & message) { return *this; }
};
EmptyLogger empty; // Can be global/static, it won't cause any race conditions as it does nothing
Logger & Logger::operator<< (Logger & (*pf)(Logger&))
{
if (logger.get_severity() < 5) // Replace with a proper condition
return empty;
return pf(*this); // What does pf() do? Aren't you returning reference to a temporary object?
}
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- C++ 与操作员不匹配<<
- 模板操作员&lt;未打电话
- C 建造者Clang STD :: Sill,找不到超载的操作员&lt;
- 为什么STD :: MAP需要操作员&lt;以及我如何写一个
- 为什么“操作员”需要const但不是为“运营商&lt;”
- 左角支架解释为操作员&lt;而不是模板参数
- 超载操作员&lt;&lt; - 必须是二进制操作员
- 为什么COUT在朋友函数中不起作用,该功能超载了操作员&lt;&lt;这是一个iStream运算符
- &lt;&lt;&lt;的这些超载有什么区别操作员
- (C 14)操作员&lt;&lt;超负荷无法正如智能指针向量所预期的那样工作
- 带有GMP的CodeBlocks,segfault with&lt;&lt;操作员和MP*_Class
- &lt;&lt;操作员在C 中超载错误
- Visual C 构建器图案插入操作员`&lt;&lt;`样式
- 超载&LT的正确方法;操作员
- 在尝试超载&lt;&lt;时链接错误2005和1169操作员
- C++标准::cout和<<操作员,优先级