【发布时间】:2020-03-06 11:15:17
【问题描述】:
实现以下调试功能的好方法是什么? 我想定义一个易于使用的函数说明符,类似于内联,它告诉编译器何时完全忽略基于启用的预处理器标志的函数。 理想情况下,我想声明这样的函数:
DEBUG_FUNCTION_VERBOSE void saveMesh(const std::string &fileName, const Mesh &mesh, ...);
DEBUG_FUNCTION_INFO void logInfo(const std::string &message);
DEBUG_FUNCTION_CHECK void checkVertexAttributes(const Mesh &mesh);
DEBUG_FUNCTION_ERROR void logError(const std::string &messageOfDoom);
有一个排序,从不太重要和缓慢到关键和更快。这个想法是我设置了一个预处理器标志,它确定启用了哪些特殊调试功能。例如,可能有一个像 DEBUG_LEVEL_CHECK 这样的标志来启用后两种类型的调试功能,或者另一个标志 DEBUG_LEVEL_VERBOSE 启用所有这些功能。 如果调试函数类型被禁用,我本质上希望编译器忽略对该函数的所有调用,包括对其参数的评估(如发布模式下的断言)。
这些功能的一个动机是加快调试速度。我想在我的代码中调用这样的调试函数并将它们留在那里。 为了控制输出和检查的内容,我宁愿使用 预处理器标志,而不是手动插入和删除对此类函数的调用。
另一个动机是在声明和调用这些函数时尽可能避免笨拙的预处理器保护。 而不是调用这样的函数:
#ifdef DEBUG_LEVEL_CHECK
checkVertexAttributes(mesh);
#endif // DEBUG_LEVEL_CHECK
我只是想正常调用函数:
checkVertexAttributes(mesh);
理想情况下,此调试方案的实现应具有以下属性: 首先,每个函数的代码中应该只有一个点,我必须声明它的调试级别(可能类似于添加像 inline 关键字这样的说明符)。其次,我只想定义一次调试级逻辑,因为它总是相同的。第三,这些调试函数具有任意上下文(属于某个类、某个命名空间或...),我可能想稍后添加这些函数。这意味着哪些函数是调试函数应该独立于调试级别逻辑本身的实现。我不想在这个地方列出所有使用的调试函数来膨胀这个逻辑。第四,如果一个函数被禁用,不仅它的执行本身而且它的参数的评估都应该被跳过(就像 assert 一样)。最后,我想方便地调用仅依赖于该逻辑的调试函数,但以透明的方式进行,如上图所示。
我看到了这个帖子: What exactly happens to empty inline functions? 但在我的情况下,这似乎会导致冗余代码,我不确定您将如何将其应用于共享相同名称的重载函数。
【问题讨论】:
-
使用普通的
#ifdef子句还不够吗?正如您链接的答案明确指出,如果相应的#define存在,它保证该行被完全忽略。 -
不,我想知道一些更简单、更透明的东西。请查看我更新的问题。
-
您的问题未更新。无论如何,最简单和最透明的更多是一种意见,因此并不适合 SO。通过使用我的答案,您至少可以获得所需的行为,而无需在多个地方更新代码。似乎和 IMO 一样容易。当然,函数签名不会显示该函数只是调试功能,但您可以在此处添加注释。这就是您寻找替代方案的原因吗?
标签: c++ debugging preprocessor compile-time