逗号在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机制不能被扩展来处理它们,就像处理括号一样。 (一些委员会成员曾经为了另一个标记而辩论,说(^...^)
,但是他们无法说服使用<...>
的大多数问题。)