我已经习惯了这个:
class Db {
_Commit(char *file, int line) {
Log("Commit called from %s:%d", file, line);
}
};
#define Commit() _Commit(__FILE__, __LINE__)
但最大的问题是我全局重新定义了Commit
这个词,而在400k行的应用程序框架中,这是一个问题。我不想使用像DbCommit
这样的特定字词:我不喜欢像db->DbCommit()
那样的冗余,或者在任何地方手动传递值:db->Commit(__FILE__, __LINE__)
最差。
那么,有什么建议吗?
答案 0 :(得分:49)
所以,你正在寻找使用file&amp ;;做日志记录(或其他东西)行信息,你宁愿不使用宏,对吧?
在一天结束时,它根本无法在C ++中完成。无论你选择什么机制 - 内联函数,模板,默认参数或其他东西 - 如果你不使用宏,你最终会得到文件名&记录功能的亚麻,而不是呼叫点。
使用宏。这是一个真正无法替换的地方。
即使C++ FAQ说宏有时也是两个邪恶中较小的一个。
正如Nathon在下面的评论中所说,在你使用宏的情况下,最好明确一下。提供宏宏名称,例如COMMIT()
而不是Commit()
。这将使维护人员和调试程序正在进行宏调用,在大多数情况下它应该有助于避免冲突。两件好事。
答案 1 :(得分:4)
等到 C++20,你可以使用 source_location
答案 2 :(得分:0)
您可以使用默认参数和预处理器技巧的组合将调用者文件传递给函数。它是以下内容:
功能声明:
static const char *db_caller_file = CALLER_FILE;
class Db {
_Commit(const char *file = db_caller_file) {
Log("Commit called from %s", file);
}
};
在类头文件中声明db_caller_file
变量。
每个翻译单元都有一个const char *db_caller_file
。它是静态的,因此它不会干扰翻译单元。 (没有多重声明)。
现在是CALLER_FILE
的东西,它是一个宏,将从gcc的命令行参数生成。实际上,如果使用自动化Make系统,其中存在源文件的通用规则,则更容易:您可以添加规则来定义宏,并将文件的名称作为值。例如:
CFLAGS= -MMD -MF $(DEPS_DIR)/$<.d -Wall -D'CALLER_FILE="$<"'
-D
定义了一个宏。
$<
是Make替换规则的先决条件的名称,在本例中是源文件的名称。因此,每个翻译单元都会拥有自己的db_caller_file
变量,其值为字符串,包含文件名。
同样的想法不适用于来电者,因为同一个翻译单元中的每个电话都应该有不同的行号。