如何使用可变参数宏附加到数组?
How to append to an array using a variadic macro?
我正在尝试使用宏来消除一堆样板代码。
这是有效的方法。我可以替换:
int do_register_script(struct context *L)
{
method_type const _instance_methods[] = {
{"new", __new},
{"delete", __delete}
{NULL, NULL}
};
register_type(L, script, _instance_methods, 0);
return 1;
}
用宏
#define do_register_type(name) \
int do_register_ ## name(struct context *L) \
{ \
method_type const _instance_methods[] = { \
{"new", __new}, \
{"delete", __delete}, \
{NULL, NULL} \
}; \
register_type(L, name, _instance_methods, 0); \
return 1; \
}
像这样:
do_register_type(script);
完美!
但我也有一些像这样的:
int do_register_rectangle(struct context *L)
{
method_type const _instance_methods[] = {
{"new", __new},
{"delete", __delete},
{"area", area},
{"perimeter", perimeter}
{NULL, NULL}
};
register_type(L, rectangle, _instance_methods, 0);
return 1;
}
现在上面的宏不起作用了。
如何向宏添加另一个参数以支持此功能?
我使用的是 C,而不是 C++,所以没有模板。
更新:此外,有时代码会使用名称的别名
{"area", area},
{"Area", area},
{"perimeter", perimeter}
{"Perimeter", perimeter}
在预处理器中遍历列表通常需要生成样板宏,但您可以通过对列表使用有点奇怪的语法来避免这种情况:
do_register_type(script, (area)(perimeter))
以下是循环此类列表的方法:
#define REG_LOOP(seq) REG_END(REG_LOOP_A seq)
#define REG_END(...) REG_END_(__VA_ARGS__)
#define REG_END_(...) __VA_ARGS__##_END
#define REG_LOOP_A(func) REG_LOOP_BODY(func) REG_LOOP_B
#define REG_LOOP_B(func) REG_LOOP_BODY(func) REG_LOOP_A
#define REG_LOOP_A_END
#define REG_LOOP_B_END
#define REG_LOOP_BODY(func) {#func, func},
REG_LOOP((foo)(bar))
将扩展为 {"foo", foo}, {"bar", bar},
。
然后你把这个宏添加到do_register_type
:
#define do_register_type(name, seq) \
int do_register_ ## name(struct context *L) \
{ \
method_type const _instance_methods[] = { \
{"new", __new}, \
{"delete", __delete}, \
REG_LOOP(seq) \
{NULL, NULL} \
}; \
register_type(L, name, _instance_methods, 0); \
return 1; \
}
你想要那个吗:
#define do_register_type(name, ...) \
int do_register_ ## name(struct context *L) \
{ \
method_type const _instance_methods[] = { \
{"new", __new}, \
{"delete", __delete}, \
__VA_ARGS__ __VA_OPT__(,) \
{NULL, NULL} \
}; \
register_type(L, name, _instance_methods, 0); \
return 1; \
}
do_register_type(script);
do_register_type(script, {"area", area}, {"perimeter", perimeter});
之前的代码在 m.c:
pi@raspberrypi:~ $ gcc -E m.c
# 1 "m.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "m.c"
# 14 "m.c"
int do_register_script(struct context *L) { method_type const _instance_methods[] = { {"new", __new}, {"delete", __delete}, {NULL, NULL} }; register_type(L, script, _instance_methods, 0); return 1; };
int do_register_script(struct context *L) { method_type const _instance_methods[] = { {"new", __new}, {"delete", __delete}, {"area", area}, {"perimeter", perimeter} , {NULL, NULL} }; register_type(L, script, _instance_methods, 0); return 1; };
pi@raspberrypi:~ $
我注意到您不希望 area 和 perimeter 的前缀“__”,与 new[ 相反=22=] 和 delete 但在某些其他情况下您可能需要它,因为它不可能自动扩展,我看到的唯一方法是明确给出代码添加
我正在尝试使用宏来消除一堆样板代码。
这是有效的方法。我可以替换:
int do_register_script(struct context *L)
{
method_type const _instance_methods[] = {
{"new", __new},
{"delete", __delete}
{NULL, NULL}
};
register_type(L, script, _instance_methods, 0);
return 1;
}
用宏
#define do_register_type(name) \
int do_register_ ## name(struct context *L) \
{ \
method_type const _instance_methods[] = { \
{"new", __new}, \
{"delete", __delete}, \
{NULL, NULL} \
}; \
register_type(L, name, _instance_methods, 0); \
return 1; \
}
像这样:
do_register_type(script);
完美!
但我也有一些像这样的:
int do_register_rectangle(struct context *L)
{
method_type const _instance_methods[] = {
{"new", __new},
{"delete", __delete},
{"area", area},
{"perimeter", perimeter}
{NULL, NULL}
};
register_type(L, rectangle, _instance_methods, 0);
return 1;
}
现在上面的宏不起作用了。
如何向宏添加另一个参数以支持此功能?
我使用的是 C,而不是 C++,所以没有模板。
更新:此外,有时代码会使用名称的别名
{"area", area},
{"Area", area},
{"perimeter", perimeter}
{"Perimeter", perimeter}
在预处理器中遍历列表通常需要生成样板宏,但您可以通过对列表使用有点奇怪的语法来避免这种情况:
do_register_type(script, (area)(perimeter))
以下是循环此类列表的方法:
#define REG_LOOP(seq) REG_END(REG_LOOP_A seq)
#define REG_END(...) REG_END_(__VA_ARGS__)
#define REG_END_(...) __VA_ARGS__##_END
#define REG_LOOP_A(func) REG_LOOP_BODY(func) REG_LOOP_B
#define REG_LOOP_B(func) REG_LOOP_BODY(func) REG_LOOP_A
#define REG_LOOP_A_END
#define REG_LOOP_B_END
#define REG_LOOP_BODY(func) {#func, func},
REG_LOOP((foo)(bar))
将扩展为 {"foo", foo}, {"bar", bar},
。
然后你把这个宏添加到do_register_type
:
#define do_register_type(name, seq) \
int do_register_ ## name(struct context *L) \
{ \
method_type const _instance_methods[] = { \
{"new", __new}, \
{"delete", __delete}, \
REG_LOOP(seq) \
{NULL, NULL} \
}; \
register_type(L, name, _instance_methods, 0); \
return 1; \
}
你想要那个吗:
#define do_register_type(name, ...) \
int do_register_ ## name(struct context *L) \
{ \
method_type const _instance_methods[] = { \
{"new", __new}, \
{"delete", __delete}, \
__VA_ARGS__ __VA_OPT__(,) \
{NULL, NULL} \
}; \
register_type(L, name, _instance_methods, 0); \
return 1; \
}
do_register_type(script);
do_register_type(script, {"area", area}, {"perimeter", perimeter});
之前的代码在 m.c:
pi@raspberrypi:~ $ gcc -E m.c
# 1 "m.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "m.c"
# 14 "m.c"
int do_register_script(struct context *L) { method_type const _instance_methods[] = { {"new", __new}, {"delete", __delete}, {NULL, NULL} }; register_type(L, script, _instance_methods, 0); return 1; };
int do_register_script(struct context *L) { method_type const _instance_methods[] = { {"new", __new}, {"delete", __delete}, {"area", area}, {"perimeter", perimeter} , {NULL, NULL} }; register_type(L, script, _instance_methods, 0); return 1; };
pi@raspberrypi:~ $
我注意到您不希望 area 和 perimeter 的前缀“__”,与 new[ 相反=22=] 和 delete 但在某些其他情况下您可能需要它,因为它不可能自动扩展,我看到的唯一方法是明确给出代码添加