将调用者 __FILE__ __LINE__ 传递给函数而不使用宏
我已经习惯了:
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__)
是最糟糕的。
那么,有什么建议吗?
I'm used to this:
class Db {
_Commit(char *file, int line) {
Log("Commit called from %s:%d", file, line);
}
};
#define Commit() _Commit(__FILE__, __LINE__)
but the big problem is that I redefine the word Commit
globally, and in a 400k lines application framework it's a problem. And I don't want to use a specific word like DbCommit
: I dislike redundancies like db->DbCommit()
, or to pass the values manually everywhere: db->Commit(__FILE__, __LINE__)
is worst.
So, any advice?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
因此,您希望使用文件和文件进行日志记录(或其他操作)。行信息,您宁愿不使用宏,对吧?
归根结底,这根本无法用 C++ 完成。无论您选择什么机制 - 无论是内联函数、模板、默认参数还是其他东西 - 如果您不使用宏,您最终都会得到文件名和文件名。日志记录函数的行号,而不是调用点的行号。
使用宏。这是他们确实无法替代的地方。
编辑:
即使 C++ FAQ 也说宏有时是两害相权取其轻。
EDIT2:
正如 Nathon 在下面的评论中所说,如果您确实使用宏,最好明确说明。为您的宏指定宏名称,例如
COMMIT()
而不是Commit()
。这将使维护者和维护者清楚地了解。调试器知道正在进行宏调用,并且在大多数情况下它应该有助于避免冲突。都是好事。So, you're looking to do logging (or something) with file & line info, and you would rather not use macros, right?
At the end of the day, it simply can't be done in C++. No matter what mechanism you chose -- be that inline functions, templates, default parameters, or something else -- if you don't use a macro, you'll simply end up with the filename & linenumber of the logging function, rather than the call point.
Use macros. This is one place where they are really not replaceable.
EDIT:
Even the C++ FAQ says that macros are sometimes the lesser of two evils.
EDIT2:
As Nathon says in the comments below, in cases where you do use macros, it's best to be explicit about it. Give your macros macro-y names, like
COMMIT()
rather thanCommit()
. This will make it clear to maintainers & debuggers that there's a macro call going on, and it should help in most cases to avoid collisions. Both good things.等到C++20,你可以使用source_location
https://en.cppreference.com/ w/cpp/utility/source_location
Wait till C++20, you cal use source_location
https://en.cppreference.com/w/cpp/utility/source_location
您可以结合使用默认参数和预处理器技巧将调用程序文件传递给函数。它如下:
函数声明:
在类头文件中声明
db_caller_file
变量。每个翻译单元都有一个
const char *db_caller_file
。它是静态的,因此不会在翻译单元之间产生干扰。 (不能多次声明)。现在是
CALLER_FILE
东西,它是一个宏,将从 gcc 的命令行参数生成。实际上,如果使用自动化的 Make 系统,其中对源文件有通用规则,则要容易得多:您可以添加一条规则来定义宏,并将文件名作为值。例如:-D
在编译此文件之前定义了一个宏。$<
是 Make 对规则先决条件名称的替换,在本例中是源文件的名称。因此,每个翻译单元都有自己的db_caller_file
变量,其值为字符串,包含文件名。相同的想法不能应用于呼叫者线路,因为同一翻译单元中的每个呼叫应该具有不同的线路号。
You can use a combination of default parameter and preprocessor trick to pass the caller file to a functions. It is the following:
Function declaration:
Declare
db_caller_file
variable in the class header file.Each translation unit will have a
const char *db_caller_file
. It is static, so it will not interfere between translation units. (No multiple declarations).Now the
CALLER_FILE
thing, it is a macro and will be generated from gcc's command line parameters. Actually if using automated Make system, where there is generic rule for source files, it is a lot easier: You can add a rule to define macro with the file's name as a value. For example:-D
defines a macro, before compiling this file.$<
is Make's substitution for the name of the prerequisite for the rule, which in this case is the name of the source file. So, each translation unit will have it's owndb_caller_file
variable with value a string, containing file's name.The same idea cannot be applied for the caller line, because each call in the same translation unit should have different line numbers.