使用 C/C++ 宏生成函数签名
Use C/C++ Macros to Generate Function Signature
我正在尝试使用 C/C++ 中的宏来生成一些样板函数声明和定义。
我想要一个类似如下的宏:
DECLARE_FUNCTION(myFunction, int, A, int, B, char, C)
生成如下代码(请忽略这段代码似乎毫无意义,它只是一个简化的例子)
void myFunction(int A, int B, char C) {
myFunction_PROXY((Variant[4]){Variant(A), Variant(B), Variant(C), Variant()});
}
void myFunction_PROXY(const Variant (&args)[4]) {
myFunction_HANDLER(args[0], args[1], args[2]);
}
void myFunction_HANDLER(int A, int B, char C) {
}
请注意我如何需要函数签名(带有类型和名称)以及在 Variant() 构造函数中使用的名称。因此,我假设我需要选择性地“循环”宏的 VA_ARGS 值以获得不同的参数组合并以不同的方式应用它们。
我已经定义了一个 class 命名的 Variant。
根据我的研究,我相信这涉及“递归宏”的某种组合,但是,我似乎无法理解如何获得我想要的输出。
任何人都可以帮助或至少指出我对 C 中的递归宏如何工作的一个很好的解释吗?
谢谢
不是很清楚它对你的情况有什么影响,你可以用__VA_ARGS__
做你想做的
#define DECLARE_FUNCTION(myFunction, ...) \
static void myFunction##_HANDLER(__VA_ARGS__) { \
\
} \
\
static void myFunction##_PROXY(const Variant (&args)[4]) { \
myFunction##_HANDLER(args[0], args[1], args[2]); \
} \
\
static void myFunction(__VA_ARGS__) { \
myFunction##_PROXY((Variant[4]){Variant(A), Variant(B), Variant(C), Variant()}); \
}
DECLARE_FUNCTION(myFunction, int A, int B, char C)
将生成
static void myFunction_HANDLER(int A, int B, char C) { }
static void myFunction_PROXY(const Variant (&args)[4]) {
myFunction_HANDLER(args[0], args[1], args[2]);
}
static void myFunction(int A, int B, char C) {
myFunction_PROXY((Variant[4]){Variant(A), Variant(B), Variant(C), Variant()});
}
免责声明 1:
老实说,我不建议你在宏背后做这样的机器。它们将成为巨大的维护负担,并且 return 是最小的。如果您可以使用其他更易于维护的抽象来做到这一点,那么在长期 运行.
中对您来说会更好
免责声明 2:
我现在正在写这个,没有编译器。我可能有语法错误,但这些是构建此解决方案的通用构建块。
免责声明说,这是可以做到的 -- 但不是很好。
这里有几个问题需要用大量的宏技巧来解决:
- 您希望扩展包含
__VA_ARGS__ / 2
的大小(在扩展时)
- 您希望
__VA_ARGS__
的扩展生成 Variant(<arg 1>), Variant(<arg 3>), Variant(<arg 5>), Variant()
- 您希望
__VA_ARGS__
的扩展生成 Variant[size]{args[0], args[1], args[2], ...}
首先,我将创建一个名为 JOIN
:
的助手
#define JOIN(a, b) JOIN_H(a, b)
#define JOIN_H(a, b) a ## b
这可能看起来很愚蠢,但它实际上所做的是确保被连接在一起的宏在被连接之前将被评估——这样被调用的宏函数将正确地实例化使用他们的结果而不是全名加入。
获取 __VA_ARGS__ / 2
的大小
获取__VA_ARGS__
的大小通常需要两个宏:
- 将
__VA_ARGS__, N, N-1, N-2, ...
传递给辅助宏,并且
- 另一个在最后提取
N
。
类似于:
#define COUNT_VA_ARGS(...) \
COUNT_VA_ARGS_H(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define COUNT_VA_ARGS_H(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N,...) N
之所以有效,是因为第一个传递了__VA_ARGS__
的所有参数,从第N个数开始倒数,然后我们提取N
.
在你的例子中,你想要 __VA_ARGS__ / 2
,所以你需要将这些参数加倍
#define COUNT_VA_ARGS(...) \
COUNT_VA_ARGS_H(__VA_ARGS__, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0)
#define COUNT_VA_ARGS_H(_1, _1, _2, _2, _3, _3, _4, _4, _5, _5, _6, _6, _7, _7, _8, _8, _9, _9, _10, _10, N,...) N
使 __VA_ARGS__
产生 Wrap(<arg 1>), Wrap(<arg 3>), ...
与 C++ 可变参数模板不同,宏不能包含可以包装每个参数的扩展表达式。要在宏中模拟它,您几乎必须显式定义 N 个扩展,然后调用它,您需要组合一个宏的结果来调用它。
#define WRAP_VA_ARGS_0(wrap)
#define WRAP_VA_ARGS_1(wrap,x0) wrap(x0)
...
#define WRAP_VA_ARGS_10(wrap,x0,x1, ..., x10) wrap(x0), wrap(x1), ..., wrap(x10)
// Call into one of the concrete ones above
#define WRAP_VA_ARGS(wrap, __VA_ARGS__) JOIN(WRAP_VA_ARGS_, COUNT_VA_ARGS(__VA_ARGS__))(__VA_ARGS__)
由于表达式实际上需要每个 other 个参数,您将再次需要将参数加倍:
#define WRAP_VA_ARGS_0(wrap)
#define WRAP_VA_ARGS_1(wrap,x0type,x0) wrap(x0)
#define WRAP_VA_ARGS_2(wrap,x0type,x0,x1type,x1) wrap(x0), wrap(x1)
...
调用 WRAP_VA_ARGS(Variant, int, A, float, B)
现在将创建 Variant(A), Variant(B)
创建索引值列表
与上面的换行类似,您需要找到一种方法来生成数字列表并将其换行。同样,这必须委托给计数包装器
#define WRAP_COUNT_VA_ARGS_0(wrap)
#define WRAP_COUNT_VA_ARGS_1(wrap) wrap[0]
#define WRAP_COUNT_VA_ARGS_2(wrap) wrap[0], wrap[1]
...
#define WRAP_COUNT_VA_COUNT_ARGS(wrap, ...) JOIN(WRAP_COUNT_VA_ARGS_, COUNT_VA_ARGS(__VA_ARGS))(wrap)
调用 WRAP_COUNT_VA_COUNT_ARGS(args, int, A, float, B)
应该生成 args[0], args[1]
综合起来
触发警告:这会很丑
#define DECLARE_FUNCTION(name, ...) \
void name(__VA_ARGS__) { \
JOIN(name, _PROXY)((Variant[COUNT_VA_ARGS(__VA_ARGS__)+1]) {WRAP_VA_ARGS(Variant,__VA_ARGS__), Variant()}); \
} \
void JOIN(name, _PROXY)(const Variant (&args)[COUNT_VA_ARGS(__VA_ARGS__) + 1]) { \
JOIN(name, _HANDLER)(WRAP_COUNT_VA_COUNT_ARGS(args, __VA_ARGS__)); \
} \
void JOIN(name, _HANDLER)(__VA_ARGS__) { \
\
}
幸运的话,DECLARE_FUNCTION(myFunction, int, A, int, B, char, C)
的例子应该产生:
void myFunction(int A, int B, char C) {
myFunction_PROXY((Variant[3+1]{Variant(A), Variant(B), Variant(C), Variant()});
}
void myFunction_PROXY(const Variant (&args)[3+1]) {
myFunction_HANDLER(args[0], args[1], args[2]);
}
void myFunction_HANDLER(int A, int B, char C) {
}
注意:数组是由常量表达式3 + 1
创建的,因为我们需要做这个算术来计算末尾的Variant()
myFunction_PROXY
的来电
不要做宏。宏不好,嗯?
使用预处理器迭代以逗号分隔的列表需要编写样板宏。
通常您必须编写或生成至少 O(n)
个宏来处理长达 n
个元素的列表。 @Human-Compiler 的答案是 O(n<sup>2</sup>)
.
您可以从 Boost.Preprocessor 中获得类似的宏,或将其用作灵感。
或者您可以对列表使用不同的语法:
DECLARE_FUNCTION(myFunction, (int,A)(int,B)(char,C))
然后您可以处理任何大小的列表,使用固定数量的宏:
#define DECLARE_FUNCTION(func_, seq_) \
void myFunction(END(PARAMS_LOOP_0 seq_)) { \
myFunction_PROXY(
(Variant[1 END(COUNT_LOOP_A seq_)]){END(VAR_LOOP_A seq_) Variant()}); \
} \
void myFunction_PROXY(const Variant (&args)[1 END(COUNT_LOOP_A seq_)]) { \
const int x = __COUNTER__+1; \
myFunction_HANDLER(END(ARR_LOOP_0 seq_)); \
} \
void myFunction_HANDLER(END(PARAMS_LOOP_0 seq_)) {}
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define PARAMS_LOOP_0(type_, name_) PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_A(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_B
#define PARAMS_LOOP_B(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_0_END
#define PARAMS_LOOP_A_END
#define PARAMS_LOOP_B_END
#define PARAMS_LOOP_BODY(type_, name_) type_ name_
#define COUNT_LOOP_A(...) COUNT_LOOP_BODY COUNT_LOOP_B
#define COUNT_LOOP_B(...) COUNT_LOOP_BODY COUNT_LOOP_A
#define COUNT_LOOP_A_END
#define COUNT_LOOP_B_END
#define COUNT_LOOP_BODY +1
#define VAR_LOOP_A(type_, name_) VAR_LOOP_BODY(name_) VAR_LOOP_B
#define VAR_LOOP_B(type_, name_) VAR_LOOP_BODY(name_) VAR_LOOP_A
#define VAR_LOOP_A_END
#define VAR_LOOP_B_END
#define VAR_LOOP_BODY(name_) Variant(name_),
#define ARR_LOOP_0(...) ARR_LOOP_BODY ARR_LOOP_A
#define ARR_LOOP_A(...) , ARR_LOOP_BODY ARR_LOOP_B
#define ARR_LOOP_B(...) , ARR_LOOP_BODY ARR_LOOP_A
#define ARR_LOOP_A_END
#define ARR_LOOP_B_END
#define ARR_LOOP_BODY args[__COUNTER__-x]
使用这些宏,DECLARE_FUNCTION(myFunction, (int,A)(int,B)(char,C))
扩展为:
void myFunction(int A, int B, char C)
{
myFunction_PROXY((Variant[1+1+1+1]){Variant(A), Variant(B), Variant(C), Variant()});
}
void myFunction_PROXY(const Variant (&args)[1+1+1+1])
{
const int x = 0+1;
myFunction_HANDLER(args[1-x], args[2-x], args[3-x]);
}
void myFunction_HANDLER(int A, int B, char C) {}
注意使用 __COUNTER__
。它不是标准 C++ 的一部分,但主要编译器支持它作为扩展。除了编写样板宏之外,您没有任何其他选项来获取连续的数组索引。
我发现您的所有回复都非常有用;在我的例子中,我需要保护一组作为旧应用程序的一部分实现的例程。
约束:互斥,尽量减少代码中的改动。
“MTX_DB_PROTECTED_FUNCTION”宏效果很好。
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define PARAMS_LOOP_0(type_, name_) PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_A(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_B
#define PARAMS_LOOP_B(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_0_END
#define PARAMS_LOOP_A_END
#define PARAMS_LOOP_B_END
#define PARAMS_LOOP_BODY(type_, name_) type_ name_
#define VAR_LOOP_0(type_, name_) VAR_LOOP_BODY(type_, name_) VAR_LOOP_A
#define VAR_LOOP_A(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_B
#define VAR_LOOP_B(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_A
#define VAR_LOOP_0_END
#define VAR_LOOP_A_END
#define VAR_LOOP_B_END
#define VAR_LOOP_BODY(type_, name_) name_
//
#define MTX_DB_PROTECTED_FUNCTION(type_, func_, seq_) \
\
static type_ _s_mtx_##func_##_protected(END(PARAMS_LOOP_0 seq_));\
\
type_ func_(END(PARAMS_LOOP_0 seq_))\
{\
UTL_AcquireMutex(__FUNCTION__, &g_h_dataFileMutex, OSL_TIMEOUT_INFINITE);\
type_ ret = _s_mtx_##func_##_protected(END(VAR_LOOP_0 seq_));\
UTL_ReleaseMutex(__FUNCTION__, &g_h_dataFileMutex);\
return ret;\
}\
\
\
static type_ _s_mtx_##func_##_protected(END(PARAMS_LOOP_0 seq_))
样本
原函数
int dummyfunc(char TabId, char checksum)
{
return 0;
}
宏插入
MTX_DB_PROTECTED_FUNCTION(int, dummyfunc, (char,TabId)(char,checksum))
{
return 0;
}
宏展开
static int _s_mtx_dummyfunc_protected(char TabId , char checksum );
int dummyfunc(char TabId , char checksum )
{
UTL_AcquireMutex(__FUNCTION__, &g_h_dataFileMutex, (unsigned long)(-1));
int ret = _s_mtx_dummyfunc_protected(TabId , checksum );
UTL_ReleaseMutex(__FUNCTION__, &g_h_dataFileMutex);
return ret;
}
static int _s_mtx_dummyfunc_protected(char TabId , char checksum )
{
return 0;
}
对于no-params函数
MTX_DB_PROTECTED_FUNCTION(int, dummyWoParams,(,))
{
基于许多其他答案和评论,以下是我想出的解决我的特定问题的方法:
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define PARAMS_LOOP_0(type_, name_) PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_A(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_B
#define PARAMS_LOOP_B(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_0_END
#define PARAMS_LOOP_A_END
#define PARAMS_LOOP_B_END
#define PARAMS_LOOP_BODY(type_, name_) type_ name_
#define VAR_LOOP_0(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_A
#define VAR_LOOP_A(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_B
#define VAR_LOOP_B(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_A
#define VAR_LOOP_0_END
#define VAR_LOOP_A_END
#define VAR_LOOP_B_END
#define VAR_LOOP_BODY(type_, name_) name_
//------------------------------------------------------------------------------
#define DEFINE_SLOT(func_, ...) \
void func_(END(PARAMS_LOOP_0 __VA_ARGS__)) { invoke(this, &func_##_SLOT END(VAR_LOOP_0 __VA_ARGS__)); }\
void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__))
#define DECLARE_SLOT(func_, ...) \
void func_(END(PARAMS_LOOP_0 __VA_ARGS__));\
void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__))
#define DECLARE_VIRTUAL_SLOT(func_, ...) \
virtual void func_(END(PARAMS_LOOP_0 __VA_ARGS__));\
virtual void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__))
#define DECLARE_SLOT_INTERFACE(func_, ...) \
virtual void func_(END(PARAMS_LOOP_0 __VA_ARGS__)) = 0;\
virtual void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__)) = 0
#define DECLARE_SLOT_OVERRIDE(func_, ...) \
void func_(END(PARAMS_LOOP_0 __VA_ARGS__)) override;\
void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__)) override
我采用了 Qt 的一些命名约定,称这些为“插槽”。
这些宏的用法如下:
//In the .h file
class MyBase {
public:
DECLARE_SLOT_INTERFACE(foo, (int, a) (int, b));
};
class MyClass : public MyBase {
public:
DECLARE_SLOT_OVERRIDE(foo, (int, a) (int, b));
DECLARE_SLOT(bar, (bool, a) (const MyClass& obj));
};
//In the .cpp file
DEFINE_SLOT(MyClass::foo, (int, a) (int, b)) {
}
DEFINE_SLOT(MyClass::bar, (bool, a) (const MyClass& obj)) {
}
我正在尝试使用 C/C++ 中的宏来生成一些样板函数声明和定义。
我想要一个类似如下的宏:
DECLARE_FUNCTION(myFunction, int, A, int, B, char, C)
生成如下代码(请忽略这段代码似乎毫无意义,它只是一个简化的例子)
void myFunction(int A, int B, char C) {
myFunction_PROXY((Variant[4]){Variant(A), Variant(B), Variant(C), Variant()});
}
void myFunction_PROXY(const Variant (&args)[4]) {
myFunction_HANDLER(args[0], args[1], args[2]);
}
void myFunction_HANDLER(int A, int B, char C) {
}
请注意我如何需要函数签名(带有类型和名称)以及在 Variant() 构造函数中使用的名称。因此,我假设我需要选择性地“循环”宏的 VA_ARGS 值以获得不同的参数组合并以不同的方式应用它们。
我已经定义了一个 class 命名的 Variant。
根据我的研究,我相信这涉及“递归宏”的某种组合,但是,我似乎无法理解如何获得我想要的输出。
任何人都可以帮助或至少指出我对 C 中的递归宏如何工作的一个很好的解释吗?
谢谢
不是很清楚它对你的情况有什么影响,你可以用__VA_ARGS__
#define DECLARE_FUNCTION(myFunction, ...) \
static void myFunction##_HANDLER(__VA_ARGS__) { \
\
} \
\
static void myFunction##_PROXY(const Variant (&args)[4]) { \
myFunction##_HANDLER(args[0], args[1], args[2]); \
} \
\
static void myFunction(__VA_ARGS__) { \
myFunction##_PROXY((Variant[4]){Variant(A), Variant(B), Variant(C), Variant()}); \
}
DECLARE_FUNCTION(myFunction, int A, int B, char C)
将生成
static void myFunction_HANDLER(int A, int B, char C) { }
static void myFunction_PROXY(const Variant (&args)[4]) {
myFunction_HANDLER(args[0], args[1], args[2]);
}
static void myFunction(int A, int B, char C) {
myFunction_PROXY((Variant[4]){Variant(A), Variant(B), Variant(C), Variant()});
}
免责声明 1:
老实说,我不建议你在宏背后做这样的机器。它们将成为巨大的维护负担,并且 return 是最小的。如果您可以使用其他更易于维护的抽象来做到这一点,那么在长期 运行.
中对您来说会更好免责声明 2:
我现在正在写这个,没有编译器。我可能有语法错误,但这些是构建此解决方案的通用构建块。
免责声明说,这是可以做到的 -- 但不是很好。
这里有几个问题需要用大量的宏技巧来解决:
- 您希望扩展包含
__VA_ARGS__ / 2
的大小(在扩展时) - 您希望
__VA_ARGS__
的扩展生成Variant(<arg 1>), Variant(<arg 3>), Variant(<arg 5>), Variant()
- 您希望
__VA_ARGS__
的扩展生成Variant[size]{args[0], args[1], args[2], ...}
首先,我将创建一个名为 JOIN
:
#define JOIN(a, b) JOIN_H(a, b)
#define JOIN_H(a, b) a ## b
这可能看起来很愚蠢,但它实际上所做的是确保被连接在一起的宏在被连接之前将被评估——这样被调用的宏函数将正确地实例化使用他们的结果而不是全名加入。
获取 __VA_ARGS__ / 2
的大小
获取__VA_ARGS__
的大小通常需要两个宏:
- 将
__VA_ARGS__, N, N-1, N-2, ...
传递给辅助宏,并且 - 另一个在最后提取
N
。
类似于:
#define COUNT_VA_ARGS(...) \
COUNT_VA_ARGS_H(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define COUNT_VA_ARGS_H(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N,...) N
之所以有效,是因为第一个传递了__VA_ARGS__
的所有参数,从第N个数开始倒数,然后我们提取N
.
在你的例子中,你想要 __VA_ARGS__ / 2
,所以你需要将这些参数加倍
#define COUNT_VA_ARGS(...) \
COUNT_VA_ARGS_H(__VA_ARGS__, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0)
#define COUNT_VA_ARGS_H(_1, _1, _2, _2, _3, _3, _4, _4, _5, _5, _6, _6, _7, _7, _8, _8, _9, _9, _10, _10, N,...) N
使 __VA_ARGS__
产生 Wrap(<arg 1>), Wrap(<arg 3>), ...
与 C++ 可变参数模板不同,宏不能包含可以包装每个参数的扩展表达式。要在宏中模拟它,您几乎必须显式定义 N 个扩展,然后调用它,您需要组合一个宏的结果来调用它。
#define WRAP_VA_ARGS_0(wrap)
#define WRAP_VA_ARGS_1(wrap,x0) wrap(x0)
...
#define WRAP_VA_ARGS_10(wrap,x0,x1, ..., x10) wrap(x0), wrap(x1), ..., wrap(x10)
// Call into one of the concrete ones above
#define WRAP_VA_ARGS(wrap, __VA_ARGS__) JOIN(WRAP_VA_ARGS_, COUNT_VA_ARGS(__VA_ARGS__))(__VA_ARGS__)
由于表达式实际上需要每个 other 个参数,您将再次需要将参数加倍:
#define WRAP_VA_ARGS_0(wrap)
#define WRAP_VA_ARGS_1(wrap,x0type,x0) wrap(x0)
#define WRAP_VA_ARGS_2(wrap,x0type,x0,x1type,x1) wrap(x0), wrap(x1)
...
调用 WRAP_VA_ARGS(Variant, int, A, float, B)
现在将创建 Variant(A), Variant(B)
创建索引值列表
与上面的换行类似,您需要找到一种方法来生成数字列表并将其换行。同样,这必须委托给计数包装器
#define WRAP_COUNT_VA_ARGS_0(wrap)
#define WRAP_COUNT_VA_ARGS_1(wrap) wrap[0]
#define WRAP_COUNT_VA_ARGS_2(wrap) wrap[0], wrap[1]
...
#define WRAP_COUNT_VA_COUNT_ARGS(wrap, ...) JOIN(WRAP_COUNT_VA_ARGS_, COUNT_VA_ARGS(__VA_ARGS))(wrap)
调用 WRAP_COUNT_VA_COUNT_ARGS(args, int, A, float, B)
应该生成 args[0], args[1]
综合起来
触发警告:这会很丑
#define DECLARE_FUNCTION(name, ...) \
void name(__VA_ARGS__) { \
JOIN(name, _PROXY)((Variant[COUNT_VA_ARGS(__VA_ARGS__)+1]) {WRAP_VA_ARGS(Variant,__VA_ARGS__), Variant()}); \
} \
void JOIN(name, _PROXY)(const Variant (&args)[COUNT_VA_ARGS(__VA_ARGS__) + 1]) { \
JOIN(name, _HANDLER)(WRAP_COUNT_VA_COUNT_ARGS(args, __VA_ARGS__)); \
} \
void JOIN(name, _HANDLER)(__VA_ARGS__) { \
\
}
幸运的话,DECLARE_FUNCTION(myFunction, int, A, int, B, char, C)
的例子应该产生:
void myFunction(int A, int B, char C) {
myFunction_PROXY((Variant[3+1]{Variant(A), Variant(B), Variant(C), Variant()});
}
void myFunction_PROXY(const Variant (&args)[3+1]) {
myFunction_HANDLER(args[0], args[1], args[2]);
}
void myFunction_HANDLER(int A, int B, char C) {
}
注意:数组是由常量表达式3 + 1
创建的,因为我们需要做这个算术来计算末尾的Variant()
myFunction_PROXY
的来电
不要做宏。宏不好,嗯?
使用预处理器迭代以逗号分隔的列表需要编写样板宏。
通常您必须编写或生成至少 O(n)
个宏来处理长达 n
个元素的列表。 @Human-Compiler 的答案是 O(n<sup>2</sup>)
.
您可以从 Boost.Preprocessor 中获得类似的宏,或将其用作灵感。
或者您可以对列表使用不同的语法:
DECLARE_FUNCTION(myFunction, (int,A)(int,B)(char,C))
然后您可以处理任何大小的列表,使用固定数量的宏:
#define DECLARE_FUNCTION(func_, seq_) \
void myFunction(END(PARAMS_LOOP_0 seq_)) { \
myFunction_PROXY(
(Variant[1 END(COUNT_LOOP_A seq_)]){END(VAR_LOOP_A seq_) Variant()}); \
} \
void myFunction_PROXY(const Variant (&args)[1 END(COUNT_LOOP_A seq_)]) { \
const int x = __COUNTER__+1; \
myFunction_HANDLER(END(ARR_LOOP_0 seq_)); \
} \
void myFunction_HANDLER(END(PARAMS_LOOP_0 seq_)) {}
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define PARAMS_LOOP_0(type_, name_) PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_A(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_B
#define PARAMS_LOOP_B(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_0_END
#define PARAMS_LOOP_A_END
#define PARAMS_LOOP_B_END
#define PARAMS_LOOP_BODY(type_, name_) type_ name_
#define COUNT_LOOP_A(...) COUNT_LOOP_BODY COUNT_LOOP_B
#define COUNT_LOOP_B(...) COUNT_LOOP_BODY COUNT_LOOP_A
#define COUNT_LOOP_A_END
#define COUNT_LOOP_B_END
#define COUNT_LOOP_BODY +1
#define VAR_LOOP_A(type_, name_) VAR_LOOP_BODY(name_) VAR_LOOP_B
#define VAR_LOOP_B(type_, name_) VAR_LOOP_BODY(name_) VAR_LOOP_A
#define VAR_LOOP_A_END
#define VAR_LOOP_B_END
#define VAR_LOOP_BODY(name_) Variant(name_),
#define ARR_LOOP_0(...) ARR_LOOP_BODY ARR_LOOP_A
#define ARR_LOOP_A(...) , ARR_LOOP_BODY ARR_LOOP_B
#define ARR_LOOP_B(...) , ARR_LOOP_BODY ARR_LOOP_A
#define ARR_LOOP_A_END
#define ARR_LOOP_B_END
#define ARR_LOOP_BODY args[__COUNTER__-x]
使用这些宏,DECLARE_FUNCTION(myFunction, (int,A)(int,B)(char,C))
扩展为:
void myFunction(int A, int B, char C)
{
myFunction_PROXY((Variant[1+1+1+1]){Variant(A), Variant(B), Variant(C), Variant()});
}
void myFunction_PROXY(const Variant (&args)[1+1+1+1])
{
const int x = 0+1;
myFunction_HANDLER(args[1-x], args[2-x], args[3-x]);
}
void myFunction_HANDLER(int A, int B, char C) {}
注意使用 __COUNTER__
。它不是标准 C++ 的一部分,但主要编译器支持它作为扩展。除了编写样板宏之外,您没有任何其他选项来获取连续的数组索引。
我发现您的所有回复都非常有用;在我的例子中,我需要保护一组作为旧应用程序的一部分实现的例程。
约束:互斥,尽量减少代码中的改动。
“MTX_DB_PROTECTED_FUNCTION”宏效果很好。
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define PARAMS_LOOP_0(type_, name_) PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_A(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_B
#define PARAMS_LOOP_B(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_0_END
#define PARAMS_LOOP_A_END
#define PARAMS_LOOP_B_END
#define PARAMS_LOOP_BODY(type_, name_) type_ name_
#define VAR_LOOP_0(type_, name_) VAR_LOOP_BODY(type_, name_) VAR_LOOP_A
#define VAR_LOOP_A(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_B
#define VAR_LOOP_B(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_A
#define VAR_LOOP_0_END
#define VAR_LOOP_A_END
#define VAR_LOOP_B_END
#define VAR_LOOP_BODY(type_, name_) name_
//
#define MTX_DB_PROTECTED_FUNCTION(type_, func_, seq_) \
\
static type_ _s_mtx_##func_##_protected(END(PARAMS_LOOP_0 seq_));\
\
type_ func_(END(PARAMS_LOOP_0 seq_))\
{\
UTL_AcquireMutex(__FUNCTION__, &g_h_dataFileMutex, OSL_TIMEOUT_INFINITE);\
type_ ret = _s_mtx_##func_##_protected(END(VAR_LOOP_0 seq_));\
UTL_ReleaseMutex(__FUNCTION__, &g_h_dataFileMutex);\
return ret;\
}\
\
\
static type_ _s_mtx_##func_##_protected(END(PARAMS_LOOP_0 seq_))
样本
原函数
int dummyfunc(char TabId, char checksum)
{
return 0;
}
宏插入
MTX_DB_PROTECTED_FUNCTION(int, dummyfunc, (char,TabId)(char,checksum))
{
return 0;
}
宏展开
static int _s_mtx_dummyfunc_protected(char TabId , char checksum );
int dummyfunc(char TabId , char checksum )
{
UTL_AcquireMutex(__FUNCTION__, &g_h_dataFileMutex, (unsigned long)(-1));
int ret = _s_mtx_dummyfunc_protected(TabId , checksum );
UTL_ReleaseMutex(__FUNCTION__, &g_h_dataFileMutex);
return ret;
}
static int _s_mtx_dummyfunc_protected(char TabId , char checksum )
{
return 0;
}
对于no-params函数
MTX_DB_PROTECTED_FUNCTION(int, dummyWoParams,(,))
{
基于许多其他答案和评论,以下是我想出的解决我的特定问题的方法:
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define PARAMS_LOOP_0(type_, name_) PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_A(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_B
#define PARAMS_LOOP_B(type_, name_) , PARAMS_LOOP_BODY(type_, name_) PARAMS_LOOP_A
#define PARAMS_LOOP_0_END
#define PARAMS_LOOP_A_END
#define PARAMS_LOOP_B_END
#define PARAMS_LOOP_BODY(type_, name_) type_ name_
#define VAR_LOOP_0(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_A
#define VAR_LOOP_A(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_B
#define VAR_LOOP_B(type_, name_) , VAR_LOOP_BODY(type_, name_) VAR_LOOP_A
#define VAR_LOOP_0_END
#define VAR_LOOP_A_END
#define VAR_LOOP_B_END
#define VAR_LOOP_BODY(type_, name_) name_
//------------------------------------------------------------------------------
#define DEFINE_SLOT(func_, ...) \
void func_(END(PARAMS_LOOP_0 __VA_ARGS__)) { invoke(this, &func_##_SLOT END(VAR_LOOP_0 __VA_ARGS__)); }\
void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__))
#define DECLARE_SLOT(func_, ...) \
void func_(END(PARAMS_LOOP_0 __VA_ARGS__));\
void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__))
#define DECLARE_VIRTUAL_SLOT(func_, ...) \
virtual void func_(END(PARAMS_LOOP_0 __VA_ARGS__));\
virtual void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__))
#define DECLARE_SLOT_INTERFACE(func_, ...) \
virtual void func_(END(PARAMS_LOOP_0 __VA_ARGS__)) = 0;\
virtual void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__)) = 0
#define DECLARE_SLOT_OVERRIDE(func_, ...) \
void func_(END(PARAMS_LOOP_0 __VA_ARGS__)) override;\
void func_##_SLOT(END(PARAMS_LOOP_0 __VA_ARGS__)) override
我采用了 Qt 的一些命名约定,称这些为“插槽”。
这些宏的用法如下:
//In the .h file
class MyBase {
public:
DECLARE_SLOT_INTERFACE(foo, (int, a) (int, b));
};
class MyClass : public MyBase {
public:
DECLARE_SLOT_OVERRIDE(foo, (int, a) (int, b));
DECLARE_SLOT(bar, (bool, a) (const MyClass& obj));
};
//In the .cpp file
DEFINE_SLOT(MyClass::foo, (int, a) (int, b)) {
}
DEFINE_SLOT(MyClass::bar, (bool, a) (const MyClass& obj)) {
}