其实C++11已经提供了lambda表达式,索性就梳理一下 co_closure.h
里一些宏定义的用法。
求宏可变参数个数:
#define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ )
#define comac_arg_n( _0,_1,_2,_3,_4,_5,_6,_7,N,...) N
#define comac_args_seqs() 7,6,5,4,3,2,1,0
#define comac_argc( ... ) comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs() )
例如 comac_argc(total,v2,m)
会有以下的展开过程:
comac_argc(total,v2,m)
/*↓*/
comac_get_args_cnt( 0, total, v2, m, 7, 6, 5, 4, 3, 2, 1, 0)
/*→ comac_arg_n(_0, _1, _2,_3,_4,_5,_6,_7, N, ...) */
/*↓*/
3
但是对于 comac_argc()
的情况,会有两个因素影响展开的结果。
如果编译时添加 -std=c++11
的选项, comac_argc()
会被展开成1。这是因为在C++11标准下,空的可变参数会被解释成 ""
。 comac_argc()
的展开过程也就变成了下面的情况:
comac_argc()
/*↓*/
comac_get_args_cnt( 0, "", 7, 6, 5, 4, 3, 2, 1, 0)
/*→ comac_arg_n(_0, _1, _2,_3,_4,_5,_6,_7, N, ...) */
/*↓*/
1
另外一个会使 comac_argc()
被展开成1的陷阱是将
#define comac_argc( ... ) comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs() )
写作
#define comac_argc( ... ) comac_get_args_cnt( 0,__VA_ARGS__,comac_args_seqs() )
这是gcc自己实现的一个特性,在gcc的文档中有这样的描述:
Second, the ‘##’ token paste operator has a special meaning when placed between a comma and a variable argument. If you write
#define eprintf(format, …) fprintf (stderr, format, ##__VA_ARGS__)
and the variable argument is left out when the eprintf macro is used, then the comma before the ‘##’ will be deleted. This does not happen if you pass an empty argument, nor does it happen if the token preceding ‘##’ is anything other than a comma.
也就是说如果 ##
写在一个逗号和 __VA_ARGS__
之间且可变参数为空的时候, ##
前的逗号会被删除。所以 comac_argc()
的展开过程是这样的:
comac_argc()
/*↓*/
comac_get_args_cnt( 0, 7, 6, 5, 4, 3, 2, 1, 0)
/*→ comac_arg_n(_0,_1,_2,_3,_4,_5,_6,_7, N, ...) */
/*↓*/
0
如果删掉了 ##
,展开过程就变为:
comac_argc()
/*↓*/
comac_get_args_cnt( 0, , 7, 6, 5, 4, 3, 2, 1, 0)
/*→ comac_arg_n(_0,_1,_2,_3,_4,_5,_6,_7, N, ...) */
/*↓*/
1