我有一个函数,其行为可能需要根据调用它的文件进行修改(例如,为了增加调试跟踪输出)。此修改需要在不重新编译的情况下完成(例如,通过编辑配置文件或更改环境变量)。
作为满足这一需求的示例,我可以写 Function()
如:
FunctionModifiable( const char* pszFile, int i );
然后这样制作一个宏:
#define Function( i ) FunctionModifiable( __FILE__, (i) )
和FunctionModifiable()
有义务检查pszFile
比如说unordered_set<>
在初始化期间填充,以查看是否需要激活特殊功能。
但是,该搜索的开销是负值(这是高性能软件,并且该函数被调用大量次),并且在这种情况下需要缓存一些每个文件的数据。我们可以消除搜索,并通过传入 not __FILE__
来获取缓存信息的存储空间。而是一个指向辅助对象的指针。该对象需要文件名,以便在进行一次性初始化时,它可以查阅配置或环境变量或让您知道它是否需要特殊处理。
FunctionHelperObject fho( __FILE__ );
#define Function( i ) FunctionModifiable( &fho, (i) ) // C-style solution
#define Function( i ) fho.MethodModifiable( (i) ) // C++-style solution
好的,现在说我想避免用户必须定义 fho
在每个文件中。 (除其他外,我们无法重写所有调用 Function() 的现有文件,尽管我们愿意重新编译它们)。
我的想法是将变量定义放入头文件中,这样任何程序都可以包含 Function()
的头文件。会得到 FunctionHelperObject fho( __FILE__ )
免费。 (这样的定义将是 #pragma once
或由预处理器变量保护。
问题是 __FILE__
此时将是 header 的名称,而不是顶级编译单元的名称。如果有一个__CFILE__
符号,这将是解决方案,但没有。
最终我能想到的最好的方法有缺点:1)“可修改”方面只能在显式编写的源代码中使用它,2)你必须进行显式编写,3)开始变得有点复杂。在代码中,您想要添加修改行为的功能,可以编写 USE_MODIFIABLE_FUNCTION
包含有问题的标题后的某个地方。这是一个创建 FunctionHelperObject
的宏上面,这次在正确的"file"中,所以 __FILE__
将具有所需的值,并且还定义了一个如上所示的宏,该宏将屏蔽不可自定义的函数 Function()
使用上面看到的两个宏之一。简而言之:前面的例子加上
#define USE_MODIFIABLE_FUNCTION FunctionHelperObject fho( __FILE__ );\n#define Function( i ) fho.MethodModifiable( (i) )
没有 USE_MODIFIABLE_FUNCTION
编写的代码只需调用不可定制的 Function()
正常方式。
但这肯定是其他一些可接受的、可移植的方式来提供这种行为吗?虽然我专门讨论了 C 预处理器,但是否有任何 C++ 模板魔法或任何其他可行的方法?
最佳答案
缓存结果。
// in the header with Function macro
static FunctionHelperObject functionhelper;
static inline void FunctionModifiableInterface(const char *file, int i) {
static initialized = 0;
if (initialized == 0) {
initialized = 1;
functionhelper = FunctionHelperObject(file);
}
FunctionModifiable(&functionhelper, i);
}
#define Function(i) FunctionModifiableInterface(__FILE__, (i))
您无法预测用户会在哪里给您打电话Function(i)
,因此您无法预测 __FILE__
的值。只需在第一次调用时初始化它,这也很棒,因为如果 Function
则不会初始化它。不被调用。你也可以这样做initialized
检查里面FunctionHelperObject
构造函数。
真正酷且难做的技巧是修改您的构建系统,以允许您传递带有已编译 C 文件的文件名的宏。因为构建系统一次编译一个 C 文件,所以这是可能的(遗憾的是编译器自己不这样做)。如果您使用cmake
与 make
后端(或者实际上只是make
本身),你可以做一些事情like this :
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__MY_FILE__='\"$(notdir $(abspath $<))\"'")
然后使用FunctionHelperObject fho(__MY_FILE__)
就像你想的那样,因为__MY_FILE__
仅取决于 make
的输出文件名.
关于C 预处理器或 C++ 魔法可以自动为每个文件创建一个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60484276/