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.
但最大的问题是我重新定义了全局提交这个词,而在一个400k行的应用程序框架中,这是一个问题。而且我不想使用像DbCommit这样的特定单词:我不喜欢db-> DbCommit()这样的冗余,或者在任何地方手动传递值:db-> Commit(__ FILE __,_ _ ____)是最差的。
So, any advice?
那么,有什么建议吗?
2 个解决方案
#1
49
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.
在一天结束时,它根本无法在C ++中完成。无论你选择什么机制 - 内联函数,模板,默认参数或其他东西 - 如果你不使用宏,你最终会得到日志函数的文件名和亚麻,而不是呼叫点。
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.
即使是C ++常见问题解答说,宏有时也是两个邪恶中的较小者。
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 than Commit()
. 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.
正如Nathon在下面的评论中所说,在你使用宏的情况下,最好明确一下。给你的宏宏名称,比如COMMIT()而不是Commit()。这将使维护人员和调试人员清楚地知道正在进行宏调用,并且在大多数情况下它应该有助于避免冲突。两件好事。
#2
0
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:
static const char *db_caller_file = CALLER_FILE; class Db { _Commit(const char *file = db_caller_file) { Log("Commit called from %s", file); } };
-
Declare
db_caller_file
variable in the class header file. Each translation unit will have aconst char *db_caller_file
. It is static, so it will not interfere between translation units. (No multiple declarations).在类头文件中声明db_caller_file变量。每个翻译单元都有一个const char * db_caller_file。它是静态的,因此它不会干扰翻译单元。 (没有多重声明)。
-
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:现在是CALLER_FILE的东西,它是一个宏,将从gcc的命令行参数生成。实际上,如果使用自动化Make系统,其中存在源文件的通用规则,则更容易:您可以添加规则来定义宏,并将文件的名称作为值。例如:
CFLAGS= -MMD -MF $(DEPS_DIR)/$<.d -Wall -D'CALLER_FILE="$<"'
函数声明:static const char * db_caller_file = CALLER_FILE; Db级{ _Commit(const char * file = db_caller_file){ 日志(“从%s调用提交”,文件); } };
-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 own db_caller_file
variable with value a string, containing file's name.
-D在编译此文件之前定义宏。 $ <是make替换规则的先决条件的名称,在本例中是源文件的名称。因此,每个翻译单元都有自己的db_caller_file变量,其值为包含文件名的字符串。< p>
The same idea cannot be applied for the caller line, because each call in the same translation unit should have different line numbers.
相同的想法不能应用于调用者行,因为同一翻译单元中的每个调用应具有不同的行号。
#1
49
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.
在一天结束时,它根本无法在C ++中完成。无论你选择什么机制 - 内联函数,模板,默认参数或其他东西 - 如果你不使用宏,你最终会得到日志函数的文件名和亚麻,而不是呼叫点。
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.
即使是C ++常见问题解答说,宏有时也是两个邪恶中的较小者。
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 than Commit()
. 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.
正如Nathon在下面的评论中所说,在你使用宏的情况下,最好明确一下。给你的宏宏名称,比如COMMIT()而不是Commit()。这将使维护人员和调试人员清楚地知道正在进行宏调用,并且在大多数情况下它应该有助于避免冲突。两件好事。
#2
0
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:
static const char *db_caller_file = CALLER_FILE; class Db { _Commit(const char *file = db_caller_file) { Log("Commit called from %s", file); } };
-
Declare
db_caller_file
variable in the class header file. Each translation unit will have aconst char *db_caller_file
. It is static, so it will not interfere between translation units. (No multiple declarations).在类头文件中声明db_caller_file变量。每个翻译单元都有一个const char * db_caller_file。它是静态的,因此它不会干扰翻译单元。 (没有多重声明)。
-
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:现在是CALLER_FILE的东西,它是一个宏,将从gcc的命令行参数生成。实际上,如果使用自动化Make系统,其中存在源文件的通用规则,则更容易:您可以添加规则来定义宏,并将文件的名称作为值。例如:
CFLAGS= -MMD -MF $(DEPS_DIR)/$<.d -Wall -D'CALLER_FILE="$<"'
函数声明:static const char * db_caller_file = CALLER_FILE; Db级{ _Commit(const char * file = db_caller_file){ 日志(“从%s调用提交”,文件); } };
-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 own db_caller_file
variable with value a string, containing file's name.
-D在编译此文件之前定义宏。 $ <是make替换规则的先决条件的名称,在本例中是源文件的名称。因此,每个翻译单元都有自己的db_caller_file变量,其值为包含文件名的字符串。< p>
The same idea cannot be applied for the caller line, because each call in the same translation unit should have different line numbers.
相同的想法不能应用于调用者行,因为同一翻译单元中的每个调用应具有不同的行号。