C pre-processor 或 C++ 魔术自动为每个文件创建一个 object?
C pre-processor or C++ magic to automatically make an object per file?
我有一个函数,其行为可能需要根据调用它的文件进行修改(例如,增加调试跟踪输出)。这种修改需要在不重新编译的情况下完成(例如,通过编辑配置文件或更改环境变量)。
作为满足此需求的示例,我可以将 Function()
写为:
FunctionModifiable( const char* pszFile, int i );
然后做一个宏:
#define Function( i ) FunctionModifiable( __FILE__, (i) )
并且 FunctionModifiable()
将有责任检查 pszFile
,比如在初始化期间填充的 unordered_set<>
,以查看是否需要激活特殊功能。
但是,该搜索的开销是一个负数(这是 high-performance 软件并且该函数被调用了很多次),并且有一些 per-file 数据需要在这种情况下被缓存。我们可以消除搜索,并获得缓存信息的存储空间,方法是传入一个指向助手 object 的指针而不是 __FILE__
。这个 object 需要文件名,这样当它进行 one-off 初始化时,它可以查询配置或环境变量或者你知道它是否需要特殊处理。
FunctionHelperObject fho( __FILE__ );
#define Function( i ) FunctionModifiable( &fho, (i) ) // C-style solution
#define Function( i ) fho.MethodModifiable( (i) ) // C++-style solution
好的,现在说我想避免用户必须在每个文件中定义 fho
。 (除其他外,我们不能 re-write 所有现有文件调用 Function(),尽管我们愿意重新编译它们)。
我的想法是在 header 文件 中放置一个变量定义的不寻常步骤,这样任何包含 header 的程序都可以用于 Function()
将免费获得 FunctionHelperObject fho( __FILE__ )
。 (这样的定义将是 #pragma once
或由预处理器变量保护。
问题是 __FILE__
在那个时候将是 header 的名称,而不是 top-level 编译单元的名称。如果有一个 __CFILE__
符号,那将是解决方案,但没有。
最终,我能想到的最好的方法有缺点:1) "modifiable" 方面只能在明确编写的源代码中使用它,以及 2) 你必须进行明确的编写, 3)开始变得有点复杂。在代码中,您想添加修改行为的能力,以便在包含有问题的 header 之后在某处写入 USE_MODIFIABLE_FUNCTION
。这将是一个创建上面 FunctionHelperObject
的宏,这次在右边 "file" 所以 __FILE__
将具有所需的值,并且还定义了一个如上所示的宏,它将掩盖non-customizable 函数 Function()
与上面看到的两个宏之一。简而言之:前面的例子,加上
#define USE_MODIFIABLE_FUNCTION FunctionHelperObject fho( __FILE__ );\n#define Function( i ) fho.MethodModifiable( (i) )
没有 USE_MODIFIABLE_FUNCTION
编写的代码将简单地以正常方式调用不可自定义的 Function()
。
但这肯定是提供此行为的其他公认的可移植方式吗?虽然我只讨论了 C 预处理器,但是否有任何 C++ 模板魔术或任何其他可行的方法?
一个选项是这样的(粗略的例子,保留 OP 中的 C++ 语法):
#define Function(i) do { \
static FunctionHelperObject obj(__FILE__); \
FunctionModifiable(&obj, (i)); \
} while (0)
请注意,如果函数有 return 值,则必须修改上述内容以适应 return 值。
另外:__FILE__
的替代方案可能是 __func__
如果它更符合您的需求。
缓存结果。
// 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
未被调用,您将不会初始化它。您可以在 FunctionHelperObject
构造函数中执行相同的 initialized
检查。
真正酷又难做的技巧是修改你的构建系统,允许你传递一个带有已编译 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
.
的输出文件名
我有一个函数,其行为可能需要根据调用它的文件进行修改(例如,增加调试跟踪输出)。这种修改需要在不重新编译的情况下完成(例如,通过编辑配置文件或更改环境变量)。
作为满足此需求的示例,我可以将 Function()
写为:
FunctionModifiable( const char* pszFile, int i );
然后做一个宏:
#define Function( i ) FunctionModifiable( __FILE__, (i) )
并且 FunctionModifiable()
将有责任检查 pszFile
,比如在初始化期间填充的 unordered_set<>
,以查看是否需要激活特殊功能。
但是,该搜索的开销是一个负数(这是 high-performance 软件并且该函数被调用了很多次),并且有一些 per-file 数据需要在这种情况下被缓存。我们可以消除搜索,并获得缓存信息的存储空间,方法是传入一个指向助手 object 的指针而不是 __FILE__
。这个 object 需要文件名,这样当它进行 one-off 初始化时,它可以查询配置或环境变量或者你知道它是否需要特殊处理。
FunctionHelperObject fho( __FILE__ );
#define Function( i ) FunctionModifiable( &fho, (i) ) // C-style solution
#define Function( i ) fho.MethodModifiable( (i) ) // C++-style solution
好的,现在说我想避免用户必须在每个文件中定义 fho
。 (除其他外,我们不能 re-write 所有现有文件调用 Function(),尽管我们愿意重新编译它们)。
我的想法是在 header 文件 中放置一个变量定义的不寻常步骤,这样任何包含 header 的程序都可以用于 Function()
将免费获得 FunctionHelperObject fho( __FILE__ )
。 (这样的定义将是 #pragma once
或由预处理器变量保护。
问题是 __FILE__
在那个时候将是 header 的名称,而不是 top-level 编译单元的名称。如果有一个 __CFILE__
符号,那将是解决方案,但没有。
最终,我能想到的最好的方法有缺点:1) "modifiable" 方面只能在明确编写的源代码中使用它,以及 2) 你必须进行明确的编写, 3)开始变得有点复杂。在代码中,您想添加修改行为的能力,以便在包含有问题的 header 之后在某处写入 USE_MODIFIABLE_FUNCTION
。这将是一个创建上面 FunctionHelperObject
的宏,这次在右边 "file" 所以 __FILE__
将具有所需的值,并且还定义了一个如上所示的宏,它将掩盖non-customizable 函数 Function()
与上面看到的两个宏之一。简而言之:前面的例子,加上
#define USE_MODIFIABLE_FUNCTION FunctionHelperObject fho( __FILE__ );\n#define Function( i ) fho.MethodModifiable( (i) )
没有 USE_MODIFIABLE_FUNCTION
编写的代码将简单地以正常方式调用不可自定义的 Function()
。
但这肯定是提供此行为的其他公认的可移植方式吗?虽然我只讨论了 C 预处理器,但是否有任何 C++ 模板魔术或任何其他可行的方法?
一个选项是这样的(粗略的例子,保留 OP 中的 C++ 语法):
#define Function(i) do { \
static FunctionHelperObject obj(__FILE__); \
FunctionModifiable(&obj, (i)); \
} while (0)
请注意,如果函数有 return 值,则必须修改上述内容以适应 return 值。
另外:__FILE__
的替代方案可能是 __func__
如果它更符合您的需求。
缓存结果。
// 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
未被调用,您将不会初始化它。您可以在 FunctionHelperObject
构造函数中执行相同的 initialized
检查。
真正酷又难做的技巧是修改你的构建系统,允许你传递一个带有已编译 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
.