使用MACRO获取函数参数的“名称”

时间:2017-09-24 08:26:41

标签: c++ function macros

我已经实现了一个日志功能,最终在整个代码中使用相同的功能。

void func(int foo, int bar){
    log_api_call("foo", foo, "bar",bar)
    ...
}

所以我决定让它变得更容易,只需提取变量名称 所以它就像是

log_api_call(foo,bar)

甚至更好

log_api_call()

它会以某种方式扩展到log_api_call("foo", foo, "bar",bar) 我甚至不知道从哪里开始“提取”函数变量名称。 非常感谢帮助。

编辑:
我理解我之前提出的问题不在于C ++预处理器功能,但是对于任意数量的参数,C MACROS可以将log_api(a,b)扩展为log_api_call("a", a, "b", b) 吗? 对于定义的数字,这项工作是微不足道的。

感谢。

4 个答案:

答案 0 :(得分:4)

这在标准C ++ 11(或标准C11 - 几乎与C ++共享其预处理器)中是不可能的。 C or C++ preprocessor不知道传递给编译器的代码的AST(因为它在实际解析代码之前运行)。

  

我甚至不知道从哪里开始提取'函数变量名。

请注意,变量和函数名称仅在编译时(预处理后)才知道。所以如果你想要它们,你需要在编译期间工作。在执行时,变量和函数名称通常会丢失(您可以strip执行可执行文件。)

你可以生成你的C ++代码(例如使用其他预处理器,如GPP或M4,或编写你自己的东西)。

您可以自定义您的C ++编译器(例如,使用GCC MELT中的扩展名或GCC插件)来自...让log_api_call调用一些新的魔法内置函数(编译器内部的处理将完成大部分工作)。这需要几个月的时间,而且非常符合编译器,我认为这不值得痛苦。

你可以解析DWARF调试信息(这也需要几个月,所以我认为这不是明智的。)

(我隐含地考虑在Linux系统上编译的C ++代码)

详细了解aspect programming

如果你想要如此强大的元编程工具,C ++是错误的编程语言。阅读更多关于Common Lisp强大宏系统的信息......

  

但是,对于任意数量的参数,C MACROS可以将log_api(a,b)扩展为log_api_call("a", a, "b", b)吗?对于定义的数字,这项工作是微不足道的。

没有。您需要一个更强大的预处理器来完成这项工作(或编写自己的工作)。对于特定需求,您可以考虑自定义source code editor(例如,在emacs编写一百行ELSP代码,在编辑时编写扩展作业 。< / p>

PS在实践中你可以找到一些库(可能boost)将参数限制在一些合理的限制

答案 1 :(得分:4)

我认为您可以从语言内部实现的最佳效果是编写一个扩展为LOG_API_CALL(foo,bar)的宏log_api_call("foo", foo, "bar", bar)

#define LOG_API_CALL(P1,P2) log_api_call(#P1,P1,#P2,P1)

如果你想用一个宏名称支持任意多个参数,这会变得非常棘手,但你也可以为每个参数数量设置一个单独的宏。

答案 2 :(得分:2)

  

它会以某种方式扩展到log_api_call("foo", foo, "bar",bar)

这在标准C ++中是不可能的。

答案 3 :(得分:2)

这实际上并不太难。

我建议稍微修改规格;而不是:

log_api_call("a", a, "b", b)展开到NAMED_VALUES(a,b)

...将"a",a,"b",b扩展到log_api(NAMED_VALUES(a,b))更有用。然后,您可以致电log_api(NAMED_VALUES(a,b),"entering function"),但您的log_api可以保持更通用(例如,// A preprocessor argument counter #define COUNT(...) COUNT_I(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1,) #define COUNT_I(_9,_8,_7,_6,_5,_4,_3,_2,_1,X,...) X // Preprocessor paster #define GLUE(A,B) GLUE_I(A,B) #define GLUE_I(A,B) A##B // chained caller #define NAMED_VALUES(...) GLUE(NAMED_VALUES_,COUNT(__VA_ARGS__))(__VA_ARGS__) // chain #define NAMED_VALUES_1(a) #a,a #define NAMED_VALUES_2(a,...) #a,a,NAMED_VALUES_1(__VA_ARGS__) #define NAMED_VALUES_3(a,...) #a,a,NAMED_VALUES_2(__VA_ARGS__) #define NAMED_VALUES_4(a,...) #a,a,NAMED_VALUES_3(__VA_ARGS__) #define NAMED_VALUES_5(a,...) #a,a,NAMED_VALUES_4(__VA_ARGS__) #define NAMED_VALUES_6(a,...) #a,a,NAMED_VALUES_5(__VA_ARGS__) #define NAMED_VALUES_7(a,...) #a,a,NAMED_VALUES_6(__VA_ARGS__) #define NAMED_VALUES_8(a,...) #a,a,NAMED_VALUES_7(__VA_ARGS__) #define NAMED_VALUES_9(a,...) #a,a,NAMED_VALUES_8(__VA_ARGS__) 可能)。这种方法也避免了零参数情况下的许多复杂情况。

vue-cli

这最多支持9个参数,但应该很容易看到如何扩展到更多。