我正在将一些跟踪和调试代码添加到我正在重构的类中.
我有一个Trace具有一定的过滤属性和方法的对象bool CanTrace(Level, , TracePropertyList = no_additional_properties)和bool Trace(Level, string, TracePropertyList = no_additional_properties).
代码中已经有很多地方使用了这个跟踪对象,并且该Trace方法的字符串参数通常是一些表达式,如果我不打算最终输出跟踪信息,我想避免评估.
重复一大堆代码
if(trace.CanTrace(LEVEL_INFO, some_props))
trace.Trace(LEVEL_INFO, consume_time().to_str(), some_props);
Run Code Online (Sandbox Code Playgroud)
是丑陋的,我想要更短的东西.
我在考虑宏
#define TRACE_WITH_PROPS(LEVEL,STRING,PROPS) //...
Run Code Online (Sandbox Code Playgroud)
和
#define TRACE(LEVEL,STRING) //...
Run Code Online (Sandbox Code Playgroud)
有一个更好的方法吗?可能使用模板或C++ 11?我不喜欢用编译器隐藏编译器中的东西,我正在尽力去除这个代码库中的其他地方的一些宏.
在C++ 11中,您可以使用闭包.你有类似的东西:
trace.Trace(LEVEL_INFO, [&](){ return format("x is %i") % ExpensiveWayToGetX(y, z); }, some_props);
Run Code Online (Sandbox Code Playgroud)
在C++ 03中,您可以使用boost.lambda hack来获得类似的效果.
但是,有一个宏包装if(trace.CanTrace(...)) trace.Trace(...)仍然稍微更高效,因为它甚至没有初始化对象与闭包将需要跟踪时所需的所有引用.我建议将宏与流接口结合起来,这样你就可以了
#define TRACE(level, some_props) \
if(!trace.CanTrace(level, some_props)) 0; \
else trace.Trace(level, some_props)
Run Code Online (Sandbox Code Playgroud)
并称之为
TRACE(LEVEL_INFO, some_props) << "x is " << ExpensiveWayToGetX(y, z);
Run Code Online (Sandbox Code Playgroud)
或定义operator()而不是operator<<和为printf样式格式:
TRACE(LEVEL_INFO, some_props)("x is %i", ExpensiveWayToGetX(y, z));
Run Code Online (Sandbox Code Playgroud)
if如果没有启用,则为0,否则实际上是跟踪,所以如果你写过它就不会吃掉其他的:
if(IsSomethingWrong())
TRACE(LEVEL_WARNING, some_props) << WhatIsWrong() << " is wrong";
else
DoSomething();
Run Code Online (Sandbox Code Playgroud)
(在宏中没有其他内容,之后的else将转到宏内部的if,但是除此之外,它将正确解析)
为了避免字符串处理,lambda 是一个很好的解决方案,如 Johannes Schaub 的回答所示。如果您的编译器尚不支持 lambda,那么您可以在没有 C++0x 功能且没有宏的情况下这样做:
doTrace(LEVEL_INFO, some_props) << "Value of i is " << i;
Run Code Online (Sandbox Code Playgroud)
doTrace 将返回一个带有虚拟运算符 << 的临时对象。如果不执行跟踪,则返回一个其operator<< 不执行任何操作的对象。否则返回一个对象,其运算符 << 执行您想要的操作。临时对象的析构函数可以发出信号,表明正在输出的字符串已完成。现在析构函数不应该抛出异常,因此如果跟踪事件的最终处理可以抛出异常,那么您可能需要包含operator<<的事件结束重载
即使没有进行跟踪,此解决方案也会导致多次虚拟函数调用,因此它的效率低于“if(tracing) ...”。这应该只在性能关键循环中真正重要,您可能无论如何都想避免进行跟踪。在任何情况下,在这些情况下或者当执行跟踪的逻辑比一系列 << 的序列更复杂时,您都可以恢复使用 if 检查跟踪。