逗号在C / C ++macros

假设我们有这样一个macros

#define FOO(type,name) type name 

我们可以使用像

 FOO(int, int_var); 

但并不总是这样简单:

 FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2 

当然我们可以这样做:

  typedef std::map<int, int> map_int_int_t; FOO(map_int_int_t, map_var); // OK 

这不是很符合人体工程学的 加types不兼容必须处理。 任何想法如何解决这个macros?

因为尖括号也可以表示(或者出现在)比较运算符<><=>= ,所以macros扩展不能忽略尖括号内的逗号,就像它在括号内一样。 (对于方括号和括号也是一个问题,即使这些方法通常以平衡对的forms出现)。可以将macros参数括在括号中:

 FOO((std::map<int, int>), map_var); 

问题是这个参数在macros扩展中保持括号,这样可以防止它在大多数情况下被作为一种types读取。

解决这个问题的一个很好的诀窍就是在C ++中,你可以使用一个函数types从一个带括号的types名称中提取一个types名称:

 template<typename T> struct argument_type; template<typename T, typename U> struct argument_type<T(U)> { typedef U type; }; #define FOO(t,name) argument_type<void(t)>::type name FOO((std::map<int, int>), map_var); 

因为形成函数types会忽略多余的括号,所以在types名称不包含逗号的情况下,可以使用带有或不带圆括号的macros:

 FOO((int), int_var); FOO(int, int_var2); 

在C中,当然这不是必须的,因为types名称不能在括号外包含逗号。 所以,对于一个跨语言的macros,你可以写:

 #ifdef __cplusplus__ template<typename T> struct argument_type; template<typename T, typename U> struct argument_type<T(U)> { typedef U type; }; #define FOO(t,name) argument_type<void(t)>::type name #else #define FOO(t,name) t name #endif 

如果你不能使用圆括号,而且你不喜欢Mike的SINGLE_ARG解决scheme,那就定义一个COMMA:

 #define COMMA , FOO(std::map<int COMMA int>, map_var); 

如果你想把一些macros参数串起来,这也是有帮助的

 #include <cstdio> #include <map> #include <typeinfo> #define STRV(...) #__VA_ARGS__ #define COMMA , #define FOO(type, bar) bar(STRV(type) \ " has typeid name \"%s\"", typeid(type).name()) int main() { FOO(std::map<int COMMA int>, std::printf); } 

打印std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE"

如果预处理器支持可变macros:

 #define SINGLE_ARG(...) __VA_ARGS__ #define FOO(type,name) type name FOO(SINGLE_ARG(std::map<int, int>), map_var); 

否则,这有点乏味:

 #define SINGLE_ARG2(A,B) A,B #define SINGLE_ARG3(A,B,C) A,B,C // as many as you'll need FOO(SINGLE_ARG2(std::map<int, int>), map_var); 

只要将FOO定义为

 #define UNPACK( ... ) __VA_ARGS__ #define FOO( type, name ) UNPACK type name 

然后用types参数的括号总是调用它,例如

 FOO( (std::map<int, int>), map_var ); 

在对macros定义的评论中举例说明调用当然是个好主意。

至less有两种方法可以做到这一点。 首先,您可以定义一个具有多个参数的macros:

 #define FOO2(type1, type2, name) type1, type2, name 

如果你这样做,你可能会发现你最终定义了更多的macros来处理更多的参数。

其次,你可以在括号中加上括号:

 #define FOO(type, name) type name F00((std::map<int, int>) map_var; 

如果你这样做,你可能会发现多余的圆括号将结果的语法弄糟。

这是可能的P99 :

 #include "p99/p99.h" #define FOO(...) P99_ALLBUTLAST(__VA_ARGS__) P99_LAST(__VA_ARGS__) FOO() 

上面的代码实际上只剥夺了参数列表中的最后一个逗号。 用clang -E检查(P99需要C99编译器)。

简单的答案是你不能。 这是模板参数select<...>的副作用; <>也出现在不平衡的上下文中,所以macros机制不能被扩展来处理它们,就像处理括号一样。 (一些委员会成员曾经为了另一个标记而辩论,说(^...^) ,但是他们无法说服使用<...>的大多数问题。)