// 下面是从libco中导出的宏
#include <iostream>
using namespace std;
/*
以下是计算参数的个数,最多支持7个参数
*/
#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_join_1( x,y ) x##y // 将两个名字变成一个字符串"xy"
#define comac_argc( ... ) comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs() )
#define comac_join( x,y) comac_join_1( x,y )
// 以下是用作重复,fun是下面typeof中的一种,重复次数取决去参数个数
#define repeat_0( fun,a,... )
#define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS__ ) repeat_0( fun,__VA_ARGS__ )
#define repeat_2( fun,a,... ) fun( 2,a,__VA_ARGS__ ) repeat_1( fun,__VA_ARGS__ )
#define repeat_3( fun,a,... ) fun( 3,a,__VA_ARGS__ ) repeat_2( fun,__VA_ARGS__ )
#define repeat_4( fun,a,... ) fun( 4,a,__VA_ARGS__ ) repeat_3( fun,__VA_ARGS__ )
#define repeat_5( fun,a,... ) fun( 5,a,__VA_ARGS__ ) repeat_4( fun,__VA_ARGS__ )
#define repeat_6( fun,a,... ) fun( 6,a,__VA_ARGS__ ) repeat_5( fun,__VA_ARGS__ )
#define repeat( n,fun,... ) comac_join( repeat_,n )( fun,__VA_ARGS__)
// 以下是功能
/*
decl_typeof宏的作用是为参数类型取别名
impl_typeof 是创建对应类型的引用
impl_typeof_cpy 是创建类型对象
con_param_typeof 是创建变量名
param_init_typeof 是通过初始化列表初始化变量
*/
#if __cplusplus <= 199711L
#define decl_typeof( i,a,... ) typedef typeof( a ) typeof_##a;
#else
#define decl_typeof( i,a,... ) typedef decltype( a ) typeof_##a;
#endif
#define impl_typeof( i,a,... ) typeof_##a & a;
#define impl_typeof_cpy( i,a,... ) typeof_##a a;
#define con_param_typeof( i,a,... ) typeof_##a & a##r,
#define param_init_typeof( i,a,... ) a(a##r),
#define co_ref( name,... ) \
repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ ) \
class type_##name \
{ \
public: \
repeat( comac_argc(__VA_ARGS__) ,impl_typeof,__VA_ARGS__ ) \
int _member_cnt; \
type_##name( \
repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \
repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__)) \
{} \
} name( __VA_ARGS__ )
int main(int argc, char **argv)
{
int total = 100;
co_ref(ref, total);
cout << ref.total << endl;
cout << comac_argc( 0, 1, 2) << endl;
return 0;
}
运行后结果
// 预处理后
typedef decltype( total ) typeof_total;
class type_ref {
public:
typeof_total & total;
int _member_cnt;
type_ref( typeof_total & totalr, ... ): total(totalr), _member_cnt(1) {}
} ref( total );
cout << ref.total << endl;
cout << 3 << endl;
下面详细解释下如何计算参数个数的
// 重点就在这三个宏
#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_args_seqs()往后移动,占用几位会移动几位
这样就会使用N永远对应着正确的数字,如果想要在增加想要计算的参数个数,可以如下
#define comac_arg_n( _0,_1,_2,_3,_4,_5,_6,_7,_8, N,...) N
#define comac_args_seqs() 8,7,6,5,4,3,2,1,0
comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs())
这个宏的第一个参数是0,意味着当无参数时会主动占用一位,此时N对应的正好是0
// 下面一步一步的展示预处理结果
comac_argc(); // 无参情况下计算参数个数
// 预处理
comac_get_args_cnt(0, comac_args_seqs())
// 预处理
//comac_arg_n(_0,_1,_2,_3,_4,_5,_6,_7, N,...)
comac_arg_n( 0, 7, 6, 5, 4, 3, 2, 1, 0);
// 此时N对应的数字正好是0,所以comac_argc()返回的结果就是0
// 当为一个参数时
comac_argc("Hello World");
comac_get_args_cnt(0,"Hello World", comac_args_seqs());
//comac_arg_n(_0, _1,_2,_3,_4,_5,_6,_7, N,...)
comac_arg_n( 0, "Hello World", 7, 6, 5, 4, 3, 2, 1, 0);
// 此时N对应的数字正好是1
后记
当第一次看见这个宏时还不清楚是干什么的,所以未在意,但是在读源码过程中发现必须得先清楚的了解这个宏后才能继续读,所以进行了分析。起初是先自行分析,发现进展不大,就写代码,预处理
但是对于comac_argc这个宏来说预处理结果就是一个数字,所以自己只能通过一步一步的替换来分析,好在功夫不负有心人,弄明白了。最后再说下libco写下这个宏的作用,其实上述是经过我删减的,libco中co_func是一个函数宏,就是给定函数名,函数体由自己实现,这个宏的作用是为协程创建闭包用的
int total = 100;
vector<int> v2;
co_ref(ref, total, v2, m);
for (int i = 0; i < 10; i++)
{
co_func(f, ref, i)
{
printf("tid: %d; ref.total %d i %d\n", gettid(), ref.total, i);
// lock
pthread_mutex_lock(&ref.m);
ref.v2.push_back(i);
pthread_mutex_unlock(&ref.m);
// unlock
}
co_func_end;
v.push_back(new f(ref, i));
}