吐槽
- 2年前, 曾经花费了巨大的精力自学了c++, 从晦涩难懂的标准库中学到了很多编程技巧(本人并不从事c++开发)应用到了项目中, 但强悍的泛型编程的思想以及技巧却一直无法展现在自己的工作中(本人从事ios), 毕竟OC实现面向对象的技术(动态,多态,反射)是和java一样的底层机制(
small talk
), 但却和c++的虚函数是完全不同的,具体可以参考 泛型
- 泛型编程是c++的一座大山, 挡住了 95% 的程序员, 这其中的95%并不是说市面是搞编程的人中只有5%在从事c++, 而是说从事c++的人中, 绝大多数并不能发挥出c++最核心的泛型的威力, 因为就事实而言, 复杂繁锁只是一方面的原因, 另一方面是国内的市场决定, 95%都是应用类型的软件, 项目中基本用不了泛型的技术
这篇文章也是兑现了3年前对自己的承诺(
当时发表OC文章时, 说要抽时间写一篇宏的文章
)废话不说了, 进入正题
C语言中的泛型思想
- c标准中有一个万能指针
void *
, 这里不再阐述, 它的作用其实是针对运行时来说的, 并不在当前的讨论范围, 严格来说并不是c++中的静态多态(当然也叫泛型)
- 真正
长的像c++中的泛型
其实是#define
, 在c98(记得好像是
)中它有了可变参数
, 至于它的语法这里也不说了, 在VC
和gcc
下对于define
的实现在展开格式上会有些编译区别, 这导致了在使用上有了巨大的差异, 这里要讨论的是gcc
下的宏, 所以相当于GNUC下的方言C
, 配合GCC下的方言语法
宏实现出了逆天的功能
回顾
这里就不再细说c++泛型相关的知识, 也不描述gcc下宏的方言, 具体看本人仓库cpp相关的部分
重头戏(ios)
利用宏简化恶心的ios代码
- OC的语法向来是特立独行的, 和其他语言的代码风格完全不同, 所以别的程序员对我们这们语言的第1反应是
傻雕语言
, 但说实话本人还恶心java那种点来点去
的语言
UIView* v = [UIView new];
//COLOR是自己定义的宏, 这里就不说了
[v setBackgroundColor:COLOR(ff0000)];
[v setFrame:CGReckMake(100,100,100,100)]
[self.view addSubview:v];
- 可能OC之父也想迎合大众语法, 所以提供了
getter,setter
的简化版本
UIView* v = [UIView new];
v.backgroundColor = COLOR(ff0000);
v.frame = CGRectMake(100,100,100,100)
[self.view addSubview:v];
这样写比较人性化, 别家的程序员也能看懂, 但若是涉及到多参时, 还是要写完整的语法
[btn setTitle:@"我是二狗" forState:1<<2];
[btn setTitle:@"我是瘪三" forState:0];
别家的代码可能是这样的优雅人性(
如安卓
)
view.setText("我是安卓小屁孩", normal);
view.setText("我是安卓狗蛋", select);
// 这里是瞎写的
所以OC 2.0出现了block(
也就是函数指针
), 各路大神发表了各种框架,学着java的点语法链式
[v mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.offset(100);
make.width.height.equalTo(@100);
}];
这种用block做成的链式编程, 我想是个人都会写, 其实也没多大技术含量, 从效率上来讲,增加了运行过程中的
函数调用开销
, 而且从本质上来讲,只是所谓的写的方便
,在内部还是调用了原生的语法, 不同类型无法用统一的书写格式,必须要定义自己的一套, 当然优点是大大简化了api的调用
但说实话, 这并不是所谓的创新, 只是和市面上95%的程序员一样的惯性思维
推导
想实现的书写格式
UILable* lab = [UILabel new];
lab.set(backgroundColor, COLOR(ff0000)
.set(text,@"我是二狗")
.set(font,Font(14)
.set(textColor, COLOL(00ff00));
上面是想实现的书写格式, 看起来是
只有一个方法set
- 传递的
第1个参数
是枚举
, 用来识别动作 - 传递的
第2个参数
是值
, 用来赋值
可以用block来封装, 但
set
这个函数的第2个参数不能统一, 因为有的可能传递对象, 有的可能传递简单类型, 所以一般封装方案是将set的第2个参数设置id
, 内部再转换
这是很惯性的思路, 没有问题
思考
- 观察其实最后本质上的代码这样的
UILabel* lab = [UILabel new];
[lab setBackgroundColor:COLOR(ff0000)];
[lab setText:@"二狗"];
[lab setFont:Font(14)];
[lab setTextColor:xxx];
这明显的可以用宏来定义这些操作
#define set(_op, _val) set##_op:(_val)
但这个宏展开后, 没法书写出
[lab
, 这几个字符, 也就没用, 所以要换个想法, 假设已经 创建好了lab
这个变量
#define set(_op, _val) [lab set##_op:(_val)]
UILabel* lab = [UILabel new];
set(Text, @"二狗");
这里发现
这样写不是很傻逼吗
- 不能
链式
- 不能
点
其实不要忘了编译器特性
#define set(_op, _val) lab._op = _val
UILabel* lab = [UILabel new];
set(next, @"二狗"); //注意这里是小写
上面只解决了点, 但说实话, 个人喜欢
标准的[]
, 因为点语法
最终还是会转换为[]
, 链式就没法了, 继续推导:
#define lab() UILabel* lab = [UILable new]; lab
#define set(_op, _val) self, [lab set##_op:(_val)], lab
lab().set(Text,@"二狗");
会被编译成
UILabel* lab = [UILabel new]; lab.self, [lab setText:@"二狗"], lab;
编译器会将宏展开到
一行显示
, 并且调用的是原生的代码, 没有一点多余的runtime
, 并且会类型检查
但有个问题就是
- 编译器报警告
未使用的lab
, 就是最后的, lab;
- 这种警告解决方案有很多, 可以配置编译警告, 这里就不说了
- 上下文中不能再现出
lab
这个变量
- 解决也简单, 添加作用域
{}
PS: 这里要说明一点, 任何OC对象都可以调用
xxx.self
__unused UILabel* lab = ({
lab().set(Text,@"二狗");
});
这里利用了
gcc方言 ({})
, 这个语法就是彻底改变UIView布局
的核心,__unused
是屏蔽未使用lab
的警告
简化版本1
需要说明的是本人使用的布局框架是
MyLayout
定义布局
#define $w(_w) myWidth = (_w), layout
#define $h(_h) myHeight = (_h), layout
#define $l(_l) myLeft = (_l), layout
#define $r(_r) myRight = (_r), layout
#define $t(_t) myTop = (_t), layout
#define $b(_b) myBottom = (_b), layout
#define $hm(_hm) myHorzMargin = (_hm), layout
#define $hs(_hs) subviewHSpace = (_hs), layout
#define $vs(_vs) subviewVSpace = (_vs), layout
#define $p(_t, _l, _b, _r) padding = (UIEdgeInsets){(_t), (_l), (_b), (_r)}, layout
#define $g(_g) gravity = (_g), layout
#define $W(_W) wrapContentWidth = (_W), layout
#define $H(_H) wrapContentHeight = (_H), layout
#define $we(_we) weight = (_we), layout
至于这个框架的使用, 这里不详谈
之所以用$
, 为了避免和程序中的其他变量重名
定义UILabel
#define $label \
UILabel* layout = [UILabel new]; \
layout
#define $ltle(_txt) text = (_txt), layout
#define $lalign(_align) textAlignment = (_align), layout
#define $lcolor(_c) textColor = (_c), layout
#define $llines(_n) numberOfLines = (_n), layout
__unused UILabel* lab = ({
$label
.$ltel(@"二狗")
.$lcolor(COLOR(ff0000));
});
case_1
__unused UILabel* grp_name_lab = ({
$label
.$lcolor(COLOR(333333))
.$lalign(1)
.$llines(1)
.$W(true)
.$H(true)
.$font(SystemFont(14))
.$t(8)
.alignment = MyGravity_Horz_Center;
layout;
});
[self.view addSubview:grp_name_lab];
以上这种书写, 要定义
UILabel
UIButton
等各自的一套, 不能统一, 但也大简化了api的调用, 并且完全是利用了编译特性, 其实它还可以继续简化, 就是定义出常用的label为宏
简化版本2
版本1其实是最简单的宏的用法
- 缺点是每种类型的(
eg:UILabe, UIButton
)都要写自己的一套所以版本2的目的是
抽象一个统一设置属性的语法
出来
抽象对象的创建
#define $V_ARG_LST_1 1
#define $V_ARG_LST_2 2, 1
#define $V_ARG_LST_3 3, 2, 1
#define $V_ARG_LST_4 4, 3, 2, 1
#define $V_ARG_LST_5 5, 4, 3, 2, 1
#define $V_ARG_LST_6 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_7 7, 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_8 8, 7, 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_9 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_10 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_11 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_12 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_13 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_14 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $V_ARG_LST_15 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $V_MAX_ARG (15)
/// !!!: 构建view --start
/** 最简单的创建view */
#define $_1(__v_type) \
__unused __v_type* layout = ({ \
__v_type* view = [_CLS(__v_type) new]; \
view; \
}); layout \
/** 通过一个存在的变量构造出 统一格式的layout */
#define $_2(__v_type, ...) \
__v_type* layout = ({(__v_type*)__VA_ARGS__;});layout
#define $V_FUN(_idx,...) $_##_idx
#define $V_FUN_IDX( _0, _1, _2, _3, _4, _5, \
_6, _7, _8, _9, _10, \
_11, _12, _13, _14, ...) \
$V_FUN(__VA_ARGS__)
#define $V_ARG(_N,...) \
$V_FUN_IDX(__VA_ARGS__, $V_ARG_LST_15)
#define $(...) \
$V_ARG($V_MAX_ARG, __VA_ARGS__, $V_ARG_LST_15)(__VA_ARGS__)
这里不解释了(
可变参数宏的高级运用
), 作用有2个:
- 创建一个新的对象,对象的类型自己指定, 并且统一对象名为通用的`layout
- 也可以调用2参数的宏, 将当前存在的对象
别名出一个通用的layout
使用如下:
// 格式1: 创建view
__unused UILabel* lab = ({
$(UILabel)
.$font(Font(13))
.$ltle(@"二狗");
});
UILabel* lab_2 = [UILabel new];
{
$(UILabel, lab_2).$xx(xx)....
}
其实这里和版本1没撒区别, 但有一点, 类型可以自己指定
统一属性设置
// 变量_val已经赋值
#define $set_1(_val) \
self, [layout s##_val:(_val)];layout
// 指定值(但不指定 类型)
#define $set_2(_mid,...) \
self, [layout s##_mid:(__VA_ARGS__)];layout
// 指定变量名 并且 指定类型
#define $set_3(_v_type, _mid, ...) \
self, [((_v_type)layout) s##_mid:(__VA_ARGS__)];((_v_type)layout)
#define $SET_FUN(_idx,...) $set_##_idx
#define $SET_FUN_IDX( _0, _1, _2, _3, _4, _5, \
_6, _7, _8, _9, _10, \
_11, _12, _13, _14, ...) \
$SET_FUN(__VA_ARGS__)
#define $SET_ARG(_N,...) \
$SET_FUN_IDX(__VA_ARGS__, $V_ARG_LST_15)
/// !!!: 通过变量赋值
#define $set(...) \
$SET_ARG($V_MAX_ARG, __VA_ARGS__, $V_ARG_LST_15)(__VA_ARGS__)
这里用
可变宏
设计出一个通用的set
这里set共有3种格式
1参数,2参数,3参数
1参数
根据很明显, 必须要有1个变量名为
etXxx
开头的变量
NSString* etText = @"二狗";
$(UILabel).$set(etText); //会被编译成 setText:etText
2参数
很容易看明白, 使用如下:
$(UILabel)
.$set(etBackgroundColor,[COLOR(0) colorWithAlphaComponent:.3])
.$set(etText, @"二狗");
这种情况下, 其实没有用到
etText
这种变量, 但若有etText
这个变量,则它会变色, 看起来更舒服
3参数
这种情况下先不说, 后面再说
定义一些全局性的必要变量
如 etText
这些UIView中常用的
.h文件
#if __OBJC__
#define $LB_UI_EXTERN(_) \
_(UIColor*, BackgroundColor) \
_(CGFloat, CornerRadius) \
_(bool, ClipsToBounds) \
_(CGFloat, Alpha) \
_(bool, Opaque) \
_(bool, Hidden) \
_(UIViewContentMode,ContentMode) \
_(bool, UserInteractionEnabled) \
_(NSInteger, Tag) \
_(MyVisibility, Visibility) \
\
\
_(MyOrientation, Orientation) \
\
\
_(NSString*, Text) \
_(UIColor*, TextColor) \
_(NSTextAlignment, TextAlignment) \
_(UIFont*, Font) \
_(NSAttributedString*,AttributedText) \
_(NSInteger, NumberOfLines) \
\
\
_(bool, Enabled) \
_(bool, Selected) \
\
\
_(NSString*, Title) \
_(CGSize, ImageSize) \
_(CGFloat, Spacing) \
_(NSMButtonImagePosition, ImagePosition) \
_(NSString*, LbTleNor) \
_(NSString*, LbTleSEL) \
_(NSString*, LbTleHig) \
_(UIColor*, LbTleColorNor) \
_(UIColor*, LbTleColorSel) \
_(UIColor*, LbTleColorHig) \
_(UIImage*, LbImgNor) \
_(UIImage*, LbImgSel) \
_(UIImage*, LbImgHig) \
_(UIImage*, LbBgIconNor) \
_(UIImage*, LbBgIconSel) \
_(UIImage*, LbBgIconHig) \
_(UIFont*, LbBtnFont) \
_(UIViewContentMode,LbBtnIconMode) \
_(NSInteger, LbLines) \
\
_(UIImage*, Image) \
\
\
_(CGFloat, MyHorzMargin) \
_(CGFloat, MyWidth) \
_(CGFloat, MyHeight) \
_(CGFloat, MyLeft) \
_(CGFloat, MyRight) \
_(CGFloat, MyTop) \
_(CGFloat, MyBottom) \
_(MyGravity, Alignment) \
_(bool, UseFrame) \
\
\
_(CGFloat, PaddingTop) \
_(CGFloat, PaddingLeft) \
_(CGFloat, PaddingRight) \
_(CGFloat, PaddingBottom) \
_(UIEdgeInsets, Padding) \
_(MyGravity, Gravity) \
_(CGFloat, SubviewSpace) \
_(CGFloat, SubviewHSpace) \
_(CGFloat, SubviewVSpace) \
_(bool, WrapContentSize) \
_(bool, WrapContentWidth) \
_(bool, WrapContentHeight) \
_(CGFloat, Weight) \
#define $LB_UI_MAKE_EXTERN(__type__,__name__) extern __type__ et##__name__;
// !!!: 生成extern
$LB_UI_EXTERN($LB_UI_MAKE_EXTERN)
这里又是宏的高级运用, VC中的宏是不行的
.m文件
#define $LB_UI_MAKE_VAR(_v_type, __name) _v_type et##__name;
// 生成全局变量
$LB_UI_EXTERN($LB_UI_MAKE_VAR);
在.h中, 只用写一遍要用的变量, 然后
extern 以及 变量的初始化
都只需要对应的宏展开就行了
简化UIView
上述创建
UILabel
等都要每次都写一遍(你可用xcode的代码生成器简化一些
)
所以完全可以再用一层宏, 来预定义一些样式
, 反正定义出来的宏, 又不占据调用时间, 不用的话编译器就不用生成, 相当于没写
#define $sty_hm_15() $hm(15)
#define $sty_hm_10() $hm(10)
#define $sty_p_10() $p(10,10,10,10)
#define $sty_p_15() $p(15,15,15,15)
#define $sty_p_20() $p(20,20,20,20)
#define $sty_g_c() $g(MyGravity_Center)
#define $sty_g_hc() $g(MyGravity_Horz_Center)
#define $sty_g_hf() $g(MyGravity_Horz_Fill)
#define $sty_g_ha() $g(MyGravity_Horz_Among)
#define $sty_g_hbw() $g(MyGravity_Horz_Between)
#define $sty_g_vc() $g(MyGravity_Vert_Center)
#define $sty_g_vf() $g(MyGravity_Vert_Fill)
#define $sty_g_va() $g(MyGravity_Vert_Among)
#define $sty_g_vbw() $g(MyGravity_Vert_Between)
/**
hm->指定
*/
#define $vauto(_hm) $ver.$H(true).$W(0).$bgcolor(CLEAR_COLOR).$hm(_hm)
/**
size == auto, 垂直居中
*/
#define $hauto() $line.$W(true).$H(true).$bgcolor(CLEAR_COLOR).$sty_g_vc()
/**
在布局视图,
h->auto
hm -> _space
v->center
*/
#define $h_hm(_space) $hauto().$W(0).$hm(_space)
/** 在布局视图中
we->1
h->auto
v->center
*/
#define $h_we() $hauto().$W(0).$we(1)
/**
h->auto,
w->auto
font->14
color->333
*/
#define $lab(_tle) $label.$W(true).$H(true).$font(SystemFont(14)).$lcolor(COLOR(333333)).$ltle(_tle)
/** h->auto
w->auto
font->12
color->999
*/
#define $lab_small(_tle) $lab(_tle).$font(SystemFont(12)).$lcolor(COLOR(999999))
/**
h->auto
w->auto
font->b18
color->333
*/
#define $lab_big(_tle) $lab(_tle).$font(BoldSystemFont(18))
#define $button(_tle) $btn.$btle(_tle,0).$bfont(SystemFont(14)).$btlecolor(COLOR(333333),0).$W(true).$H(true)
/** image相关 */
#define $iv_img(_img,_w,_h) $(NSMImageView).$set(etImage, (_img)).$set(etMyWidth,(_w)).$set(etMyHeight,(_h)).$set(etContentMode,2)
/** flow */
#define $flw(_num) __unused MyFlowLayout* layout = [MyFlowLayout flowLayoutWithOrientation:(0) arrangedCount:(_num)]; layout
#define $vflow(_num,_hs,_vs) $flw((_num)).$g(MyGravity_Horz_Fill).$hs((_hs)).$vs((_vs)).$H(true)
/** float */
#define $vfla() __unused MyFloatLayout* fl = [MyFloatLayout floatLayoutWithOrientation:0]; layout
#define $vfloat(_hs, _vs) $fla().$hs((_hs)).$vs((_vs))
/// !!!: 以下这几个宏建议不要再用了
#define $lab_f_14() $label.$set(etFont, SystemFont(14)).$cset($$CLR_LAB_0xf).$W(true).$H(true)
#define $lab_3_14() $label.$set(etFont, SystemFont(14)).$cset($$CLR_LAB_0x333).$W(true).$H(true)
#define $lab_6_14() $label.$set(etFont, SystemFont(14)).$cset($$CLR_LAB_0x666).$W(true).$H(true)
#define $lab_9_14() $label.$set(etFont, SystemFont(14)).$cset($$CLR_LAB_0x999).$W(true).$H(true)
/** 宽高auto, 颜色为333 */
#define $btn_fff(_img, _font, _tle) $btn.$cset($$CLR_BTN_NOR_0xf).$set(etLbTleNor,(_tle)).$set(etLbImgNor,(_img)).$set(etLbBtnFont, (_font)).$W(true).$H(true)
#define $btn_333(_img, _font, _tle) $btn.$cset($$CLR_BTN_NOR_0x333).$set(etLbTleNor,(_tle)).$set(etLbImgNor,(_img)).$set(etLbBtnFont, (_font)).$W(true).$H(true)
#define $btn_666(_img, _font, _tle) $btn.$cset($$CLR_BTN_NOR_0x666).$set(etLbTleNor,(_tle)).$set(etLbImgNor,(_img)).$set(etLbBtnFont, (_font)).$W(true).$H(true)
#define $btn_999(_img, _font, _tle) $btn.$cset($$CLR_BTN_NOR_0x999).$set(etLbTleNor,(_tle)).$set(etLbImgNor,(_img)).$set(etLbBtnFont, (_font)).$W(true).$H(true)
使用
$hauto().$hs(5); //自己体会
整体一起来
定义几个宏, 它们的作用自己体会
// !!!: 挂载
//当前作用域下的 layout挂载到当前 正在写代码的这个类的当前对象self中(setter)
#define $mount(_key) self; [self set##_key:layout]; layout
// !!!: 指定当前layout的父view
#define $super(_v) \
self, [(_v) addSubview:layout], layout
// !!!: 当前layout指定添加一个子view
#define $add(_sub_v) \
self,[layout addSubview:(_sub_v)], layout
// !!!: 寻找子view
/// 在当前layout中根据指定的tag找到它的子view
/// 这个会将当前的layout重新赋值到找到的子view, 若没有找到, 则layout就为nil了, 就芭比Q了
/// 找到后, 后续的layout其实已经变了, 若想setter, 则调用 3个参数的 $set, 指定类型(第1个参数)
#define $get(_tag) \
self, layout = (typeof(layout))[layout viewWithTag:(_tag)], layout
// !!!: 重新获取顶层的 layout
#define $root(_super, _tag) self, layout = [(_super) viewWithTag:(_tag)], layout
// 为当前的layout设置一个 别名
#define $alias(_type, _ov, _nv) self; __unused _type _nv = ({(_type)_ov;}); layout
// !!!: 执行一段代码
// eg: $(UIView).$exs{
// ... code
// }$exe();
// exs ===> excute start 代码开始
// exe ===> excute_ended 代码结束
#define $exs self, (
#define $exe() ), layout
使用
$hauto().$hs(5)
.$add(({
$btn_fff(IMAGE(user-ined-lw-gold), SystemFont(11), subar[index]).$H(false).$h(16).$W(0).$w(45);
ViewCorner(layout, 8);
layout;
}))
.$add({
$lab_f_14().$set(etFont,SystemFont(11)).$ltle(array[index]).$cset($$V_TAG_1971);
})
.$add(({
$iv_img(IMAGE(newcenter_img_jt), 8, 8);
}))
.$set(etBackgroundColor,[COLOR(0) colorWithAlphaComponent:.3])
.$H(0).$h(20).$corner(10).$set(etClipsToBounds, true).$super(tmp_v);
就这么简单, 这些宏完全可以再由自己去扩展, 去简化, 去重命名
全部是在编译时, 由编译器推导出来, 并且全部是原生的方法, 效率没的说
在C语言中做出tuple
构造tuple的结构
#define $TUPLE_ARG_LST_1 1,1
#define $TUPLE_ARG_LST_2 2,2, 1,1
#define $TUPLE_ARG_LST_3 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_4 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_5 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_6 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_7 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_8 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_9 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_10 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_11 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_12 12,12, 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_13 13,13, 12,12, 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_14 14,14, 13,13, 12,12, 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_15 15,15, 14,14, 13,13, 12,12, 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_MAX_ARG (30)
#define $tuple_def_1(_name, _val, ...) \
struct{ \
typeof(_val) _name; \
};
// 如果注释下面的, 打开这个, 则编译器生成的结构
///// 是类与类之间组合的结构, 自己可以打开这个,注释下面的然后编译试一试
//#define $tuple_def_2(_name, _val, ...) \
// $tuple_def_1(__VA_ARGS__) \
// struct{ \
// typeof(_val) _name; \
// };
#define $tuple_def_2(_name, _val, ...) \
struct{ \
$tuple_def_1(__VA_ARGS__) \
typeof(_val) _name; \
};
#define $TUPLE_FUN(_idx,...) $tuple_def_##_idx
#define $TUPLE_FUN_IDX( _0,_1, \
_2,_3, \
_4,_5, \
_6,_7, \
_8,_9, \
_10,_11, \
_12,_13, \
_14,_15, \
_16,_17, \
_18,_19, \
_20,_21, \
_22,_23, \
_24,_25, \
_26,_27, \
_28,_29, \
...) \
$TUPLE_FUN(__VA_ARGS__)
#define $TUPLE_ARG(_N,...) \
$TUPLE_FUN_IDX(__VA_ARGS__, $TUPLE_ARG_LST_15)
#define $tuple(_var, ...) \
struct{ \
$TUPLE_ARG($TUPLE_MAX_ARG,__VA_ARGS__, $TUPLE_ARG_LST_15)(__VA_ARGS__) \
}__unused _var
$tuple(aaa,age,10); //__code_1
__code_1
会被编译成 :
struct{
struct{
struct{
typeof(20.) money;
};
typeof(10) age;
};
}__attribute__((__unused__)) aaa;
格式完全和tuple一致
真正的tuple(同时赋值)
#define $TUPLE_ARG_LST_1 1,1
#define $TUPLE_ARG_LST_2 2,2, 1,1
#define $TUPLE_ARG_LST_3 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_4 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_5 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_6 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_7 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_8 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_9 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_10 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_11 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_12 12,12, 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_13 13,13, 12,12, 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_14 14,14, 13,13, 12,12, 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_ARG_LST_15 15,15, 14,14, 13,13, 12,12, 11,11, 10,10, 9,9, 8,8, 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1
#define $TUPLE_MAX_ARG (30)
#define $tuple_def_1(_name, _val) \
struct{ \
typeof(_val) _name; \
};
//#define $tuple_def_2(_name, _val, ...) \
// $tuple_def_1(__VA_ARGS__) \
// struct{ \
// typeof(_val) _name; \
// };
#define $tuple_def_2(_name, _val, ...) \
struct{ \
$tuple_def_1(__VA_ARGS__) \
typeof(_val) _name; \
};
#define $TUPLE_FUN(_idx,...) $tuple_def_##_idx
#define $TUPLE_FUN_IDX( _0,_1, \
_2,_3, \
_4,_5, \
_6,_7, \
_8,_9, \
_10,_11, \
_12,_13, \
_14,_15, \
_16,_17, \
_18,_19, \
_20,_21, \
_22,_23, \
_24,_25, \
_26,_27, \
_28,_29, \
...) \
$TUPLE_FUN(__VA_ARGS__)
#define $TUPLE_ARG(_N,...) \
$TUPLE_FUN_IDX(__VA_ARGS__, $TUPLE_ARG_LST_15)
#define $tuple_set_1(_name,_val,...) \
._name = (_val)
#define $tuple_set_2(_name,_val, ...) \
$tuple_set_1(__VA_ARGS__), \
._name = (_val) \
#define $TUPLE_SET_FUN(_idx,...) $tuple_set_##_idx
#define $TUPLE_SET_FUN_IDX( \
_0,_1, \
_2,_3, \
_4,_5, \
_6,_7, \
_8,_9, \
_10,_11, \
_12,_13, \
_14,_15, \
_16,_17, \
_18,_19, \
_20,_21, \
_22,_23, \
_24,_25, \
_26,_27, \
_28,_29, \
...) \
$TUPLE_SET_FUN(__VA_ARGS__)
#define $TUPLE_SET_ARG(_N,...) \
$TUPLE_SET_FUN_IDX(__VA_ARGS__, $TUPLE_ARG_LST_15)
#define $tuple_set(...) = { \
$TUPLE_SET_ARG($TUPLE_MAX_ARG,__VA_ARGS__, $TUPLE_ARG_LST_15)(__VA_ARGS__) \
}
#define $tuple(_var, ...) \
struct{ \
$TUPLE_ARG($TUPLE_MAX_ARG,__VA_ARGS__, $TUPLE_ARG_LST_15)(__VA_ARGS__) \
}__unused _var $tuple_set(__VA_ARGS__)
$tuple(aaa,age,10,money, 20.);
编译器会编译成
struct{
struct{
struct{
typeof(20.) money;
};
typeof(10) age; };
}__attribute__((__unused__)) aaa = {
.money = (20.),
.age = (10)
};
这种tuple, 在构造结构体时,
类的层次结构和c++中的tuple继承体系结构是一样的
, 但是tuple的取值有问题
, 因为在书写时, 先写的10, 再写的20, 在tuple中取值的顺序应该是get<0> 对应的是10, get<1>对应的是20
,但最后赋值时顺序却是 第0个对应-->20, 第1个对应-->10
, 但这种不用考虑, 因为指定了变量名, 下面是真正意义上的tuple
真正的tuple
以下这些宏, 是真正在C语言中实现了tuple, 其中对宏的运用已经到了出神入化的境界了
#define $TUPLE_ARG_LST_1 1
#define $TUPLE_ARG_LST_2 2, 1
#define $TUPLE_ARG_LST_3 3, 2, 1
#define $TUPLE_ARG_LST_4 4, 3, 2, 1
#define $TUPLE_ARG_LST_5 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_6 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_7 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_8 8, 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_9 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_10 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_11 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_12 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_13 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_14 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_ARG_LST_15 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
#define $TUPLE_MAX_ARG (15)
#define $TUPLE_SET_FUN_NUM(_idx,...) $$_##_idx
#define $TUPLE_SET_FUN_IDX_NUM( \
_0,_1, \
_2,_3, \
_4,_5, \
_6,_7, \
_8,_9, \
_10,_11, \
_12,_13, \
_14, \
...) \
$TUPLE_SET_FUN_NUM(__VA_ARGS__)
// !!!: tuple 定义
#define $tuple_def_1(_val, _num, ...) \
struct{ \
typeof(_val) _num; \
}
#define $tuple_def_2(_v1, _v2, _n1, _n2, ...) \
struct{ \
$tuple_def_1(_v2, _n2); \
typeof(_v1) _n1; \
}
#define $tuple_def_3( \
_v1, _v2, _v3, _n1, _n2, _n3, ...) \
struct{ \
$tuple_def_2(_v2, _v3, _n2, _n3); \
typeof(_v1) _n1; \
}
#define $tuple_def_4( \
_v1, _v2, _v3, \
_v4, \
_n1, _n2, _n3, \
_n4,...) \
struct{ \
$tuple_def_3( \
_v2, _v3, _v4, \
_n2, _n3, _n4 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_5( \
_v1, _v2, _v3, \
_v4, _v5, \
_n1, _n2, _n3, \
_n4, _n5,...) \
struct{ \
$tuple_def_4( \
_v2, _v3, _v4, \
_v5, \
_n2, _n3, _n4, \
_n5 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_6( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_n1, _n2, _n3, \
_n4, _n5, _n6,...) \
struct{ \
$tuple_def_5( \
_v2, _v3, _v4, \
_v5, _v6, \
_n2, _n3, _n4, \
_n5, _n6 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_7( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, ...) \
struct{ \
$tuple_def_6( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_n2, _n3, _n4, \
_n5, _n6, _n7 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_8( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, _v8, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, _n8, ...) \
struct{ \
$tuple_def_7( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_v8, \
_n2, _n3, _n4, \
_n5, _n6, _n7, \
_n8 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_9( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, _v8, _v9, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, _n8, _n9, ...) \
struct{ \
$tuple_def_8( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_v8, _v9, \
_n2, _n3, _n4, \
_n5, _n6, _n7, \
_n8, _n9 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_10( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, _v8, _v9, \
_v10, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, _n8, _n9, \
_n10, ...) \
struct{ \
$tuple_def_9( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_v8, _v9, _v10, \
_n2, _n3, _n4, \
_n5, _n6, _n7, \
_n8, _n9, _n10 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_11( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, _v8, _v9, \
_v10,_v11, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, _n8, _n9, \
_n10, _n11,...) \
struct{ \
$tuple_def_10( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_v8, _v9, _v10, \
_v11, \
_n2, _n3, _n4, \
_n5, _n6, _n7, \
_n8, _n9, _n10, \
_n11 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_12( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, _v8, _v9, \
_v10,_v11,_v12, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, _n8, _n9, \
_n10, _n11, _n12,...) \
struct{ \
$tuple_def_11( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_v8, _v9, _v10, \
_v11,_v12, \
_n2, _n3, _n4, \
_n5, _n6, _n7, \
_n8, _n9, _n10, \
_n11, _n12 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_13( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, _v8, _v9, \
_v10,_v11,_v12, \
_v13, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, _n8, _n9, \
_n10, _n11, _n12, \
_n13, ...) \
struct{ \
$tuple_def_12( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_v8, _v9, _v10, \
_v11,_v12,_v13, \
_n2, _n3, _n4, \
_n5, _n6, _n7, \
_n8, _n9, _n10, \
_n11, _n12,_n13 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_14( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, _v8, _v9, \
_v10,_v11,_v12, \
_v13, _v14, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, _n8, _n9, \
_n10, _n11, _n12, \
_n13, _n14, ...) \
struct{ \
$tuple_def_13( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_v8, _v9, _v10, \
_v11,_v12,_v13, \
_v14, \
_n2, _n3, _n4, \
_n5, _n6, _n7, \
_n8, _n9, _n10, \
_n11, _n12,_n13, \
_n14 \
); \
typeof(_v1) _n1; \
}
#define $tuple_def_15( \
_v1, _v2, _v3, \
_v4, _v5, _v6, \
_v7, _v8, _v9, \
_v10,_v11,_v12, \
_v13, _v14, _v15, \
_n1, _n2, _n3, \
_n4, _n5, _n6, \
_n7, _n8, _n9, \
_n10, _n11, _n12, \
_n13, _n14, _n15, ...) \
struct{ \
$tuple_def_14( \
_v2, _v3, _v4, \
_v5, _v6, _v7, \
_v8, _v9, _v10, \
_v11,_v12,_v13, \
_v14,_v15, \
_n2, _n3, _n4, \
_n5, _n6, _n7, \
_n8, _n9, _n10, \
_n11, _n12,_n13, \
_n14, _n15 \
); \
typeof(_v1) _n1; \
}
#define $TUPLE_FUN(_idx,...) $tuple_def_##_idx
#define $TUPLE_FUN_IDX( \
_0,_1, \
_2,_3, \
_4,_5, \
_6,_7, \
_8,_9, \
_10,_11, \
_12,_13, \
_14, \
...) \
$TUPLE_FUN(__VA_ARGS__)
#define $TUPLE_ARG(_N,...) \
$TUPLE_FUN_IDX(__VA_ARGS__, $TUPLE_ARG_LST_15)
// !!!: tuple同时赋值
#define $tuple_set_1(_val,...) \
(_val)
#define $tuple_set_2(_val, ...) \
$tuple_set_1(__VA_ARGS__), \
(_val) \
#define $tuple_set_3(_val, ...) \
$tuple_set_2(__VA_ARGS__), \
(_val)
#define $tuple_set_4(_val, ...) \
$tuple_set_3(__VA_ARGS__), \
(_val)
#define $tuple_set_5(_val, ...) \
$tuple_set_4(__VA_ARGS__), \
(_val)
#define $tuple_set_6(_val, ...) \
$tuple_set_5(__VA_ARGS__), \
(_val)
#define $tuple_set_7(_val, ...) \
$tuple_set_6(__VA_ARGS__), \
(_val)
#define $tuple_set_8(_val, ...) \
$tuple_set_7(__VA_ARGS__), \
(_val)
#define $tuple_set_9(_val, ...) \
$tuple_set_8(__VA_ARGS__), \
(_val)
#define $tuple_set_10(_val, ...) \
$tuple_set_9(__VA_ARGS__), \
(_val)
#define $tuple_set_11(_val, ...) \
$tuple_set_10(__VA_ARGS__), \
(_val)
#define $tuple_set_12(_val, ...) \
$tuple_set_11(__VA_ARGS__), \
(_val)
#define $tuple_set_13(_val, ...) \
$tuple_set_12(__VA_ARGS__), \
(_val)
#define $tuple_set_14(_val, ...) \
$tuple_set_13(__VA_ARGS__), \
(_val)
#define $tuple_set_15(_val, ...) \
$tuple_set_14(__VA_ARGS__), \
(_val)
#define $TUPLE_SET_FUN(_idx,...) \
$tuple_set_##_idx
#define $TUPLE_SET_FUN_IDX( \
_0,_1, \
_2,_3, \
_4,_5, \
_6,_7, \
_8,_9, \
_10,_11, \
_12,_13, \
_14, \
...) \
$TUPLE_SET_FUN(__VA_ARGS__)
#define $TUPLE_SET_ARG(_N,...) \
$TUPLE_SET_FUN_IDX(__VA_ARGS__, $TUPLE_ARG_LST_15)
#define $tuple_set(...) = { \
$TUPLE_SET_ARG($TUPLE_MAX_ARG,__VA_ARGS__, $TUPLE_ARG_LST_15)(__VA_ARGS__) \
}
#define $tuple(_var, ...) \
$TUPLE_ARG( \
$TUPLE_MAX_ARG,__VA_ARGS__, \
$TUPLE_ARG_LST_15 \
) \
( \
__VA_ARGS__, \
$_1,$_2,$_3,$_4,$_5,$_6,$_7,$_8,$_9,$_10,$_11,$_12,$_13,$_14,$_15 \
)\
__unused _var $tuple_set(__VA_ARGS__)
#endif
assign_code{
// $tuple(v_1, @"二狗");
// BLOG((v_1.$_1));
//
//
// $tuple(v_2, CGRectMake(0, 0, 100, 100));
// BLOG(v_2.$_1.size.height);
//
// $tuple(v_3, @"我是二狗", "他是瘪三儿", @10);
struct{
struct{
struct{
struct{
typeof(1002202) $_4;
};
typeof("我爱吃狗肉") $_3;
};
typeof("C字符串") $_2;
};
typeof(@"二狗") $_1;
} __attribute__((__unused__)) v_4 = { (1002202), ("我爱吃狗肉"), ("C字符串"), (@"二狗") };
$tuple(v_4,@"二狗","C字符串", "我爱吃狗肉",1002202);
}
总结
- 以上就是本人掌握的
宏的使用技巧
, 这些技巧需要花费大量的精力去研究, 说白了就是跳出传统的思维, 这些使用技巧在当今的网络中基本没人拿出来介绍, 包括在国外, 所以也是一笔宝贵的经验,当然这些利用宏实现的所谓的泛型, 过程相当复杂, 在C++中,实现出来有自己的泛型编译支持, 同时更为复杂和强大,学无止境, 编程的路上只有往下学才能掌握本质的东西