【发布时间】:2021-05-18 06:52:03
【问题描述】:
如果在“logger.h”文件中我有这个:
template <int CompileTimeVerbosity>
struct Logger
{
static inline int compileTimeVerbosity = CompileTimeVerbosity;
void log(const std::string& msg) { }
};
#define LOG(logger, msgVerbosity, msg) \
if constexpr (msgVerbosity >= logger.compileTimeVerbosity) \
{ \
logger.log(msg); \
} \
inline Logger<4> loggerObj;
我将此标头包含在一堆 .cpp 文件中。然后在其中一个中我做:
void func()
{
LOG(loggerObj, 2, std::string("Sorry, you called a ") + std::to_string(int()) + " on a " + std::to_string(int()))
}
因为内联 Logger loggerObj 被指示只定义一次,并且我们在多个 .cpp 文件中包含头文件,所以我们不知道它是在哪里定义的。我们只知道编译器在“一些”.cpp 中定义了一次。因此,当我们在某些 .cpp 中调用 func() 时,“loggerObj”标识符可能类似于“extern Logger loggerObj;”。如果是这种情况,我是否正确地说编译器当时没有完整的定义?这也意味着 func() 函数中的所有内容都将被编译,然后只有链接器可以针对可能在另一个翻译单元中定义的对象执行 if constexpr 语句。
我不确定这是否是链接时优化,但是 LOG() 宏调用中的内容应该很容易被链接器优化,对吧?换句话说,生成的代码不应包含 std::string() + std::string() 等?
虚幻引擎有与此类似的日志系统,但我认为它可能完全在宏级别上工作,所以在宏调用 UELog(category, verbosity, msg) 我认为整行只是被预处理器省略而不是复制一些东西比如 if constexpr。
有什么办法可以做到这一点吗?我找不到这部分日志系统的源代码。
【问题讨论】:
-
“链接器可以执行 if constexpr 语句” - 不,
if constexpr将在编译步骤中评估 -
if constexpr是不是的正确工具。它一点也不像#if。 -
@user7860670 真的吗?那是因为它知道来自 extern Logger logger1 的模板类型; ?或者它在任何情况下都能做到吗?因为我认为编译器会编译单个翻译单元中的内容,而链接器会完成其余的工作,因此当找不到标记为 extern 的变量时,为什么会出现链接器错误,而不是编译器错误。
-
@StoryTeller-UnslanderMonica 如果'verbosityLevel'较低,他们都会删除那段代码,只是一个在预处理器步骤从源代码中删除它,另一个从编译代码中删除它在编译器步骤,对吧?
-
没有。这是一个常见的误解。 stackoverflow.com/q/46512248/817643
标签: c++ preprocessor