在我们的应用程序中,我们创建了自己的日志系统。在这个日志系统中有几种不同的日志类型,调试、错误、警告、通信、性能等等。有很多#ifdef和#endif来禁用特定的日志类型。这些#ifdef和#endif使代码难以阅读。
我们正在考虑删除这些#ifdef和#endif,并在将消息写入文件之前进行检查。这意味着对日志系统有很多“无用”的调用。这些调用不会导致任何写入活动。
如果没有这些#ifdef和#endif这些“无用”调用,是否有更好的方法来打开/关闭日志类型? AND
以下情况如何:
// comment out if not needed
#define ENABLE_LOG
#ifdef ENABLE_LOG
# define LOG(x) x
#else
# define LOG(x) (void) 0
#endif
稍后您可以致电:
LOG(mylogger.call());
#else
按照 Dietrich Epp 的建议更新了该部分。
除了#define
效果很好的解决方案之外,我还想介绍一个使用模板的替代方案
template<bool B>
void log(std::string message){}
template<>
void log<true>(std::string message){log_internal(message);}
#define DEBUG true
#define COMMUNICATION false
...
log<DEBUG>("this message will be logged");
log<COMMUNICATION>("this message won't");
该#define
解决方案在大多数情况下确实很棒,但使用此解决方案有一些原因:
您可能需要范围界定 - 即不要让您的log
设备弄脏全局命名空间。这个解决方案可以放在一个不能的namespace
地方。#define
您可能需要更严格地控制可以做什么和不可以做什么。定义的LOG(x)
问题是任何东西都可以放入x
- 如果关闭日志记录,您将看不到问题。
澄清 - 您的代码可能会编译和使用
LOG(std::cout << "Here!" << endl);
因为此特定日志已关闭。但是从现在起 2 年后的某一天,有人会打开日志记录并endl undefined
在整个地方得到错误。或者更糟 - 他可能会发现突然打开日志记录需要链接到一个早已不复存在的库(因为该日志记录专门调用了该库中定义的函数),或者使用了一个很久以来就改变了接口的函数(甚至被完全删除了!真实的故事 :( )
编辑
我被要求将其添加到答案中:
在您不记录的情况下(空函数),似乎存在函数调用开销。当编译器对其进行优化时,情况并非如此。如果您想确定这一点 -inline
向函数添加指令。
此外,您可能希望将其从 an 更改std::string
为 aconst char *
以确保没有调用字符串构造函数 - 但这也应该由编译器自动优化。
无论如何,就像我说的那样,这本质上并不比#define
解决方案更好。实际上,我仍然#define
在我的项目中使用 - 但在某些特定情况下,此模板解决方案更可取。