![](/img/trans.png)
[英]C++ - style passing caller file and line to function (equivalent of __FILE__ and __LINE__)
[英]Passing the caller __FILE__ __LINE__ to a function without using macro
我已经习惯了:
class Db {
_Commit(char *file, int line) {
Log("Commit called from %s:%d", file, line);
}
};
#define Commit() _Commit(__FILE__, __LINE__)
但最大的问题是我在全球范围内重新定义了Commit
这个词,在 40 万行的应用程序框架中这是一个问题。 而且我不想使用像DbCommit
这样的特定词:我不喜欢像db->DbCommit()
这样的冗余,或者在任何地方手动传递值: db->Commit(__FILE__, __LINE__)
是最糟糕的。
那么,有什么建议吗?
因此,您希望使用文件和行信息进行日志记录(或其他操作),并且您宁愿不使用宏,对吗?
归根结底,它根本无法在 C++ 中完成。 无论您选择什么机制——内联函数、模板、默认参数或其他东西——如果你不使用宏,你最终只会得到日志函数的文件名和行号,而不是呼叫点。
使用宏。 这是它们真正不可替代的地方。
甚至C++ FAQ 也说宏有时是两害相权取其轻的。
正如 Nathon 在下面的评论中所说,在您确实使用宏的情况下,最好明确说明它。 给你的宏宏命名,比如COMMIT()
而不是Commit()
。 这将使维护人员和调试人员清楚地知道有一个宏调用正在进行,并且在大多数情况下应该有助于避免冲突。 两样好东西。
等到 C++20,你可以使用 source_location
您可以使用默认参数和预处理器技巧的组合将调用者文件传递给函数。 它是以下内容:
函数声明:
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
变量,其值为一个字符串,包含文件名。
相同的想法不能应用于呼叫者线路,因为同一翻译单元中的每个呼叫应该具有不同的行号。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.