d模板元编程笔记02
元 元名(T,U,V) 如 (限制条件 T, U 或 V)
{...
}元 限制(T)如 (是(T : 整)) { /*...*/ } // #1
元 限制(T)如 (是(T : 串)) { /*...*/ } // #2
元 限制(T,U)如 (是(T : 整) && !是(U : 浮)) { /*...*/ } // #3
元 限制(T,U)如 (是(T : 整) && 是(U : 浮)) { /*...*/ } // #4别名 限制!(整) C1; // #1
// 别名 限制!(串) C2; // 错误,无声明 适应 (串)
别名 限制!(整,串) C3;// #3 和 #4 考虑, 但 #4 是 丢弃. // 所以是#3 T 函数(T)(T 实参)如 (是(T : 整) || 是(T : 双精))
{ 中 实参; }构 构(T)如 (是(T : 整) || 是(T : 双精))
{ /*...*/ }类 类(T)如 (是(T : 整) || 是(T : 双精)): 基类!T, 接口1
{ /*...*/ }
类模板,限制条件在继承
之前.在限制
中只知道类型
,如果需要值,用T.初化
.限制
是编译时结构.
动 两次调用(别名 函数, T)(T 参)//能 函数(函数(一些 T))吗?//应该不行的如 (是(的型({函数(函数(T.初化));}())))
{中 函数(函数(参));
}
概念.类似c++
的概念,必须满足的条件(不变量(本质)
),聚集起来叫概念
.实例化前,要检测这些条件.
导入 标.区间;构 区间包装器(区间)如 (是输入区间!区间)//符合输入区间的概念吗?
{/* 区间至少有三个成员函数:.前(), .弹前() 和 .空的().*/
}//工厂函数
动 区间包装器(区间)(区间 区间) 如 (是输入区间!区间)
{中 区间包装器!(区间)(区间);
}
类似编译时,接口
,编译时鸭子类型
.只要满足编译时接口
就行,如(输入区间
).
元 临时(T)
如 (是(T:整))// #1, 特定 对 整
{ /*...*/ }元 临时(T) // #2, 通用
{ /*...*/ }别名 临时!整 TI;// 错误!
很奇怪,不应该,c++
是按最匹配
来匹配的.与模板限定
不一样.这个是限制
.
是不可能不断的给最通用的加限制.
元 临时(T) // #2, 通用的变成这个可怕模样,如 ( !(是(T:整[]))&& !是区间!T&& !是(T:双精[n], 整 n))
{ ... }
结合起来:
元 特定(T : U[], U)
{ ... }元 限制(T) 如 (是(T : U[], U))
{ ... }元 静如化(T)
{静 如 (是(T : U[], U)){ ... }异 //停止编译静断(0, "不能实例化静如化.");
}
限制
比特化
强,你可用是(...)
测试特化
,静如
也非常强大.当然c++已学习过来了,(如 常式)
.
特化
移植c++代码
时很强,而且有多个特化时,找最特化
,而限制
不是这样的,冲突了就冲突了.所以d不限制你
,你随意用就行了.他们都是强大的工具
.
当你重复输入是表达式或其他限制时
,可以用模板
抽象了.测试能否编译用__特征(编译,q{代码})
元 是可序化(类型)
{静 如 (__特征(编译, {类型 类型;大小型 数 = 类型.序化;}))枚 极 是可序化 = 真;异枚 极 是可序化 = 假;
}
模块 有算术操作;元 有算术操作(类型)
{静 如 (__特征(编译,{类型 t, 结果;结果 = t + t; // 加结果 = t - t; // 减法结果 = t * t; // 乘积结果 = t / t; // 除法结果 = +t; // 一元 +结果 = -t; // 一元 -}))//类似概念了.枚 极 有算术操作 = 真;异枚 极 有算术操作 = 假;
}静 断定(有算术操作!整);
静 断定(有算术操作!双精);构 S {}
静 断定(!有算术操作!S);
用一个模板,抽象出了限制
条件.更强大的是串插件
.有算术操作/可序化
还可再抽象.
构 变平(区间) 如 (是输入区间!区间)
{/* 与先前相同代码 */静 如 (是前向区间!区间)变平 保存() @属性{中 本;}
}
不能在非区间上实例化,原来可以绕过
,现在不行了.
如果是前向区间
,增加了函数.这样如果T
是前向区间
,则变平!T
也是前向区间
了.相当于你也拥有了前向区间的一切能力
,而你只写了一小片代码.你也可以同样扩展变平
为双向区间
,但你需要引入后子区间(backSubRange)
成员来跟踪区间的反向状态
.
模板元组.即(T...)
.这个特性
大家都喜欢啊.AA曾经说...是个垃圾.现在变废为宝啦
.
目前的T...
,仍然必须在最后啊.元组将吸收类型,别名,字面量
,太多了.一堆,但值得,简单,灵活
.是的.c++
里面最爽的,现在也是这个...
了.D模板元组
有个编译时.长度
成员.可用标准用法,如[i],切片,$
.
元 去前(T...)
{静 如 ( T.长度 > 0// .长度. >0&& 是(T[0] == 整)) // 索引别名 T[1..$] 去前; // 切片异别名 空 去前;
}别名 去前!(整, 双精, 串) 更短;
静 断定(是( 更短[0] == 双精));
静 断定(是( 更短[1] == 串));//编译时
元 示范元组(T...)
{别名 T 示范元组;
}单元测试
{示范元组!(串, 整, 双精) t;断定(t.长度 == 3);t[0] = "abc";t[1] = 1;t[2] = 3.14;动 t2 = t[1..$];断定(t2[0] == 1);断定(t2[1] == 3.14);空 福(整 i, 双精 d) {}福(t2); // 好.双精[] 数组 = [t2]; // 见, [和]之间断定(数组 == [1.0, 3.14]);
}
元 元组类型(T...)
{别名 T 元组类型; //暴露T
}别名 元组类型!(整, 串, 双精) ISD;
静 断定(是( 元组类型!(ISD[0], ISD[1], ISD[2]) == ISD ));
别名 元组类型!(整, 串, 双精) ISD;
别名 元组类型!(ISD, ISD) 双整串精;静 断定(是(双整串精 == 元组类型!(整,串,双精,整,串,双精)));
自动变平
了.不嵌套
.不好:无树类型元组
,本来可以更强大.当然连接元组是方便了.如需要递归/分支
,可用元组
,还有多态树
元组可以迭代.c++
现在是靠((式),...);
可迭代值及类型
,
导入 标.类型元组;单元测试
{别名 元组类型!(串, 整, 双精) T;T t;t[0] = "abc";t[1] = 1;t[2] = 3.14;串[T.长度] s;每一(索引, 类型; T) // 类型上迭代.{静 如(是(类型 == 双精))s[索引] = 类型.的串;}断定(s == ["", "", "双精"]);空 条(T)(引用 T d) { T t; d = t;}每一(索引, 值; t) // 迭代值.不同位置不同类型{条(t[索引]); // 用 t[i索引],而不是'值'来访问引用}//不是用`值`来取断定(t[0] == "");断定(t[1] == 0);导入 标.数学;断定(标.数学.是非数(t[2]));
}
可创建
和命名
这种类型值,几乎是一类
,但有两点:
无声明元组的内置符号.这种元组
不能从函数返回,得用std.typecons.Tuple
包装.T.的串
可返回串,整,双精
,但不能用(串,整,双精) t
来构造元组.但如果有元组!(串,整,双精) t
,就可以了.
区分模板元组参数,(类型,表达,函数参数)元组
,
T...
包含:类型/表达式(值)
元组.让你可以声明类型元组的变量
.类型元组
只包含类型
.
函数参数元组
用来保存函数参数
..的元组
属性是类/构
的包含成员值
的元组
成员名元组
.用__特征(成员,一些类型)
包含所有一些类型
的成员名,是串,(方法,构造器,别名)
.
类型元组
,可包含值/类型
.大元组/小元组
是预定义构/函数(模板)
,用来操纵元组
导入 标.类型元组;
别名 元组类型!(空) 空;
别名 元组类型!() 空的;
静 断定( !是(空 == 空的) );//两个不一样.
静 断定(!是( 元组类型!(整, 空, 串) == 元组类型!(整, 串)));
零元组与一元组.
串 到串(串 分隔 = ", ", 实参...)(实参 实参)
{导入 标.转换;串 结果;每一(索引, 实参; 实参){结果 ~= 到!串(实参);如 (索引 != 实参.长度 - 1)结果 ~= 分隔; //最后一个不加分隔.}中 结果;
}单元测试
{断定( 到串(1, "abc", 3.14, 'a', [1,2,3])== "1, abc, 3.14, a, [1, 2, 3]");
}
整 多少(实参...)(实参 实参)如 (实参.长度 > 1 && 实参.长度 < 10)
//限制模板参数/数量,用限制.
{中 实参.长度; // == 实参.长度
}
你有很多区间
.
导入 标.区间, 标.算法;
导入 是所有区间;空 弹所有前(区间...)(引用 区间 区间)如(是所有区间!区间)//限定条件
{每一(索引, 区间; 区间)区间[索引].弹前; // 取引用访问
}//适用于任何区间单元测试
{动 数组1 = [0,1,2];动 数组2 = "你好, 世界!";动 数组3 = 映射!"a*a"(数组1);弹所有前(数组1, 数组2, 数组3);断定(数组1 == [1,2]);断定(数组2 == "你好, 世界!");断定(相等( 数组3, [1,4]));
}
元 是所有区间(区间...)
{静 如 (区间.长度 == 0) // 基例: 停止.枚 是所有区间 = 真;异 静 如 (!是输入区间!(区间[0])) // 找到非区间:停止.枚 是所有区间 = 假;异 // 继续递归枚 是所有区间 = 是所有区间!(区间[1..$]);
}//经典递归
类似c++的元与值
,对lisp,scheme,haskell
友好,初化清单常量
为,在较短元组
上调用模板取得的值,
元 的名(T)
{枚 串 的名 = T.的串;
}元 的名(别名 a)
{枚 串 的名 = a.的串;
}单元测试
{断定(的名!(双精[]) == "双精[]");整 i;断定(的名!(i) == "i");
}
元 的名(T...) 如 (T.长度 == 1) // 限制1个实参
{//枚 串 的名 = T[0].的串;
}//稍微简化
类型参数不接受符号
,而别名不接受类型参数
,所以得重复,而元组可接收类型/别名
.现在可能改了
.
继承列表,得更新了
.
类型元组,调整继承列表,先定义自己为到类型元组的别名
的模板,再让类从模板
继承.
接口 I {}
接口 J {}
接口 K {}
接口 L {}类 基A {}
类 基B {}元 继承(基) 如 (是(基 == 类))
{静 如 (是(基 : 基A))别名 元组类型!(基, I, J, K) 继承;异 静 如 (是(基 : 基B))别名 元组类型!(基, L) 继承;异别名 基 继承;
}//继承别名为`元组类型`// 从基继承
类 我的类 : 继承!基A { /*...*/ }
类 我的其他类 : 继承!基B { /*...*/ }
在基类
模板化,也可全局枚
上模板化.
导入 标.类型元组;元 消除(类型, 目标元组...)
{静 如 (目标元组.长度 == 0) // 耗尽元组,别名 目标元组 消除; // 完成工作.异 静 如 (是(目标元组[0] : 类型))别名 消除!(类型, 目标元组[1..$]) 消除;异别名 元组类型!(目标元组[0], 消除!(类型, 目标元组[1..$])) 消除;//挨个递减
//这行,难点.第1个不是要消除类型时,要保留它
}单元测试
{别名 元组类型!(整,双精,整,串) 目标;别名 消除!(整, 目标) 无整;静 断定(是( 无整 == 元组类型!(双精, 串) ));
}
消除!(类型, 类型0, 类型1, 类型2, ...)
->
类型0, 消除!(类型, 类型1, 类型2, ...)
消除,特定类型.
元 无重复(类型...)
{静 如 (类型.长度 == 0)别名 类型 无重复; // No 类型, 没什么 到 干.异别名 元组类型!(类型[0], 无重复!(消除!(类型[0], 类型[1..$]))) 无重复;
}静 断定(是( 无重复!(整,双精,整,串,双精)== 元组类型!(整,双精,串)));
去重
.思路很简单.从第1个开始,把后面所有与之相同的类型去掉.不断循环.标准库里面有.
取给定类
的继承列表.
元 父列表(类) 如 (是(类 == 类))
{静 如 (是(类 父 == 父))别名 元组类型!(父, 父列表!父) 父列表;
}// 对对象,是(对象 父 == 父))给出空类型元组
元 父列表()
{别名 元组类型!() 父列表;
}单元测试
{类 A {}类 B : A {}类 C : A {}类 D : C {}静 断定(是(父列表!对象 == 元组类型!()));静 断定(是(父列表!A== 元组类型!(对象)));静 断定(是(父列表!B== 元组类型!(A, 对象)));静 断定(是(父列表!D== 元组类型!(C, A, 对象)));
}
元 检查继承(基)
{别名 检查实现!(基).结果 检查继承;
}元 检查实现(基)
{// 重写
}// 它工作!
类 无错误 : 检查继承!(我的类) { /*...*/ }
重载运算符.
福 二元操作(串 操作:"+")(...) { ... }
构 数字(T) 如 (是数值!T)
{T 数;
}
模块 数字;
导入 标.特征;构 数字(T) 如 (是数值!T)
{T 数;动 二元操作(串 操作, U)(U u)如 ((操作 == "+" || 操作 == "-" || 操作 == "*" || 操作 == "/")&& ((是数值!U) || 是(U u == 数字!V, V))){插件("别名 的型(a" ~ 操作 ~ "b) 结果;静 如 (是数值!U)中 数字!结果(a"~操作~"b);异中 数字!结果(a"~操作~"b.数);");}
}
允许你一次定义多个操作符.
操作 | 定义成员模板 |
---|---|
一元
|
+, -, ++, --, * 和 ~
|
opu
|
opUnary(串 s)() if (s == "op")
|
opu[i0]
|
opIndexUnary(串 s)(size_t i0) if (s == "op")
|
opu[i0, i1]
|
opIndexUnary(串 s)(size_t i0,size_t i1) if (s == "op")
|
opu[i0, i1, in]
|
opIndexUnary(串 s)(size_t i0, ...) if (s == "op")
|
opu[i..j]
|
opSliceUnary(串 s)(size_t i, size_t j) if (s == "op")
|
opu[]
|
opSliceUnary(串 s)() if (s == "op")
|
二元
|
+, -, *, /, %, ^^, ~, in, &, |, ^, <<, >> 和 >>>
|
u op v
|
opBinary(串 s, V)(V v) if (s == "op")
|
v op u
|
opBinaryRight(串 s, V)(V v) if (s == "op")
|
赋值
|
+, -, *, /, %, ^^, ~, &, |, ^, <<, >> 和 >>> (无 in)
|
u op = v
|
opOpAssign(串 s, V)(V v) if (s == "op")
|
索引
|
+, -, *, /, %, ^^, ~, &, |, ^, <<, >> 和 >>> (无 in).
|
u[i0, i1, in] op = v
|
opIndexOpAssign(串 s, V)(V v, size_t i0, ...)if (s == "op")
|
切片
|
+, -, *, /, %, ^^, ~, &, |, ^, <<, >> 和 >>> (无 in).
|
u[i..j] op = v
|
opSliceOpAssign(串 s, V)(V v, size_t i, size_t j)if (s == "op")
|
u[] op = v
|
opSliceOpAssign(串 s, V)(V v)if (s == "op")
|
cast(T)u
|
T opCast(T)()
|
算术运算
福 二元操作(串 操作:"+")(...) { ... }
用串插件
一次生成多个
操作符,作为模板参数,可编译时折叠常量
,同时数字遵守提升规则
.数字!整+数字!双精->数字!双精
插件模板
目前,所有模板都在声明处实例化.插件模板
的不同在于:代码在调用点处实例化
,所以他们的使用方式与以前模板不一样.
插件 元 新功能(T,U) { ... }
//声明/* 实例 */
类 我的类(T,U,V)
{插件 新功能!(U,V);...
}
插件 元 连接()
{元组!(的型(本), U) 二元操作(串 操作, U)(U u)如 (操作 == "~"){中 元组(本, u);}
}//写完了这个,就什么时候都可用了.
很类似万能的宏
,对不对?语法及使用,都是在普通模板前加个插件(mixin)
,你仍然拥有其余所有模板
功能(限制,默认值
).在本地域
完成查找符号,调用时包含结果代码
,因而注入
功能.
类,构,函数
模板不能单独成插件模板
,必须把他们包装在标准模板
中.也没有了同名模板
技巧了.照着标准模板
写就是了.
现在不要混用标准模板
与插件模板
.已经严格区分他们了,插件模板
就是为了代替宏
的.如结构中无继承
,你得想办法.也可在插件模板
中加功能/策略
来生成代码
.
插件模板中代码
可能无意义如本/未定义符号
,他们只是语法正确的D代码
,把他们当作宏
就对了.用来复制/粘贴
来避免冗余代码
.
构 S
{插件 连接;
}
单元测试
{S s,t;动 结果 = s ~ t;断定(结果 == 元组(s,t));
}
获得串联功能.主要思想就是只写一次代码
.提供给任何客户域
想要的功能
.如算法操作,转换,日志,注册
,等任何新成员,操作,
,反正随意.就像你的宏,到处写得飞起.你可以到处使用他们函数,模块域,其他模板,构,类...
.限制是他们都注入到本地域
,在类中他们不能加不变量
语句,在函数中不能加进/出
语句,但可把他们注入不变/进/出
语句中.
公 插件 元 出版者插件()
{//实现订阅与退订导入 标.函数 : 至闭包;导入 标.标io;别名 空 闭包(对象 发送器, 串 事件) 回调;别名 空 函数(对象 发送器, 串 事件) 回调函数;极[回调] 回调; // 整[0][回调]可能更小//注册订阅空 注册(回调 回调){// 确保未注册订阅 .如 (回调 在 回调)写行("是已注册订阅 .");异回调[回调] = 真; //从;}// 通过函数针注册订阅 .空 注册(回调函数 回调函数){注册( 至闭包(回调函数) );}// 移除订阅空 未注册(回调 回调){如 (回调 在 回调)回调.移除(回调);异写行("尝试移除未知回调.");}// 通过函数针移除订阅 .空 未注册(回调函数 回调函数){未注册(至闭包(回调函数));}// 通知所有订阅者空 通知(对象 从, 串 事件){每一 ( 回调 cb, 极 原 ; 回调 ){cb( 从, 事件 );}}
}插件 元 栈插件()//提供标准栈操作
{// 取父类型别名 的型(本) 我;静 我[] 栈;保护:@属性 极 空的() { 中 栈.长度 == 0; }@属性 大小型 数() { 中 栈.长度; }空 压(我 元素){栈 ~= 元素;}我 弹(){我 元素 = 偷看();栈.长度 -= 1;中 元素;}我 偷看(){如 ( 栈.长度 == 0 )抛 新 异常("在空栈上偷看.");我 元素 = 栈[栈.长度-1];中 元素;}
}
注意,D允许本地(局部)导入
,使功能作为完整整体,别名 的型(本) 我
,非常好用,将取得我
的正确类型,然后提供合适(通用)的功能
.
我们用定义好的本
注入任何结构,用类
来显示,也继承了插件
.
类 友栈
{私 串 名;私 整 年龄;// 我们插件插件 栈插件;插件 出版者插件;空 压友(串 名, 整 年龄){// 为栈创建新实例 动 人 = 新 友栈();人.名 = 名;人.年龄 = 年龄;压(人);//通知所有订阅者通知(人, "压");}//弹空 弹友(){动 人 = 弹();通知( 人, "弹");}// 订阅方法空 在屋信息(对象 发送器, 串 消息){动 p = 转换(友栈)发送器;写格式行("订阅: 屋 , 名: %s, 年龄: %s, 消息: %s \n",p.名, p.年龄, 消息);}
}类 扩展友栈 : 友栈 // 我们贵宾(vip)
{私 极 是开发者;// 压空 压友(串 名, 整 年龄, 极 D){// 为栈创建新实例 动 x人 = 新 扩展友栈();x人.名 = 名;x人.年龄 = 年龄;x人.是开发者 = D;压(x人);// 通知所有订阅者通知(x人, "压");}
}
空 推特(对象 发送器, 串 消息)
{动 p = 转换(友栈)发送器;写格式行("订阅: 推特, 名: %s, 年龄: %s, 消息: %s \n",p.名, p.年龄, 消息);
}空 掘客(对象 发送器, 串 消息)
{动 p = 转换(友栈)发送器;写格式行("订阅: 掘客, 名: %s, 年龄: %s, 消息: %s \n",p.名, p.年龄, 消息);
}空 邮件(对象 发送器, 串 消息)
{动 p = 转换(友栈)发送器;写格式行("订阅: e邮件, 名: %s, 年龄: %s, 消息: %s \n",p.名, p.年龄, 消息);
}//扩展结束 友栈 订阅 函数//包含额外 --是开发者-- 信息.
空 博客(对象 发送器, 串 消息)
{如 ( 转换(扩展友栈)发送器 ){动 p = 转换(扩展友栈)发送器;写格式行("订阅: 博客, 名: %s, 年龄: %s, 是 开发者 ?: %s, 消息: %s \n",p.名, p.年龄, p.是开发者, 消息);}异{写行("博客仅对贵宾,消息转发至电邮");邮件(发送器, 消息);// 下转 是 也 可能//动 p = 转换(友栈)发送器;//写格式行("订阅: 博客, 名: %s, 年龄: %s, 消息: %s \n",//p.名, p.年龄, 消息);}
}
模块 用友;
导入 友;空 主()
{动 p = 新 友栈();动 p2 = 新 扩展友栈();// 注册一些订阅者.p.注册( &推特 );p2.注册( &推特 );p2.注册( &博客 );p2.注册( &博客 );// 压和弹p.压友( "阿来", 19 );p.压友( "汤姆", 55);p2.压友( "汉斯", 42, 假);p2.压友( "沃特", 101, 真);p.弹友();p2.弹友();p2.弹友();p.未注册( &推特 );p2.未注册( &推特 );p.注册( &博客 );p.压友( "阿里克斯", 33 );
}
开发者栈,继承了用户栈
的插件
,基类有插件
,继承类都有了.既是堆栈
,也是发布者
,通过别名 的型(本)
,继承者可包含额外信息
.
... 分发操作(串 名)()
... 分发操作(串 名, 参)(参 参)
... 分发操作(串 名, 实参...)(实参 实参)
分发操作,也可使用
模板限制.名,参数
上限制
当类型有opDispatch
且无定义成员时,用这个.做为最后的备份.
构 分发器
{整 福(整 i) { 中 i*i;}串 分发操作(串 名, T...)(T t){中 "分发激活: " ~ 名 ~ ":" ~ 元组类型!(T).的串;}
}空 主()
{分发器 d;动 i = d.福(1); //编译器查找福, 调用 福.动 s1 = d.注册("abc"); //无注册成员 -> 分发操作 激活;断定(s1 == "分发激活: 注册:(串)");动 s2 = d.空的; // 无空成员,无实参.断定(s2 == "分发 激活: 空的:()");
}
类 取置
{私 整 i;私 整 j;私 双精 d;私 串 串;动 分发操作(串 名)() // 无参版本 -> 取器如 (名.长度 > 3 && 名[0..3] == "取"){枚 串 成员 = 名[3..$]; // "取x3" -> "X3"//我们测试是否存在 "X3": 是(的型(本.X3)) 为真静 如 (__特征(编译,插件("是(的型(本." ~ 成员 ~ "))")))插件("中 " ~ 成员 ~ ";");异静 断定(0, "取置错误: 无成员调用 " ~ 成员);}动 分发操作(串 名, 参)(参 参) // 置器如 (名.长度 > 3 && 名[0..3] == "置"){枚 串 成员 = 名[3..$]; // "置x3" -> "X3"// 我们测试是否可赋值给"成员".本.成员 = 参.初化静 如 (__特征(编译, 插件("{" ~ 成员 ~ " = 参.初化;}"))){插件(成员 ~ " = 参;");插件("中 " ~ 成员 ~ ";");}异静 断定(0, "取置 错误: 无成员调用" ~ 成员);}//
}单元测试
{动 gs = 新 取置();gs.置i(3);动 i = gs.取i;断定(i == 3);gs.置串("abc");断定(gs.取串 == "abc"); // "abc"
}
你有一堆成员,但不想直接给,而是通过取/置
来给.
任何构/类
都可以这样办.在分发代码前后加些函数
.如对所有函数都加个打印(函数名)
.再加一个开关,作为控制.
记录日志.方法:
将Type包装到Logger结构中.
获取Type.tupleof.
对此调用typeof.
opDispatch测试wrap.foo()是否合法.
别名 本.
模块 透明;构 透明(T)
{T 值;别名 值 本;
}// 工厂函数
透明!T 透明(T)(T t)
{中 透明!T(t);
}
模块 用透明;
导入 透明;空 主()
{动 i = 透明(10);断定(i == 10);// 等价 测试i = 1; // 从整赋值 ++i; // ++i.值,上动作断定(i == 2);// 接受整 函数整 福(整 ii) { 中 ii+1;}断定(福(i) == 3); // 函数调用整 真整 = i; // 传输其值断定(真整 == 2);断定(i == 2);断定(i == 真整);// 连续调用折叠为1个.i = 透明(透明(i));
}
断定(是(的型(i) == 透明!整));//仍然是.表现得很像整
构 薄(T)
{T 值;别名 值 本;
}薄!T 薄(T)(T t)
{中 薄!T(t);
}单元测试
{动 i = 透明(10);动 t = 薄(i); // 工作.断定(t == 10); // 啊, 值传输正确.断定(是(的型(t) == 薄!(透明!整)));
}
还可以加包装器,不过感觉间接层
太多,无意义
当然,完美子类型,别名 本
是自动的,类似继承
,而op分发
则要自己写需要代码
构 描述符(T)
{T 值;别名 值 本;串 描述() @属性{导入 标.转换;中 "描述符支持" ~ T.的串~ "值 " ~ 到!串(值) ~ ".\n"~ "(的大小: " ~ 到!串(T.的大小) ~ " 字节)";}
}空 主()
{动 d = 描述符!双精(1.0);写行(d.描述); // "描述符支持双精的大小: 8 字节)"
}
别名 本
限制为1个了.
枚 关系 { 独立, 父, 子, 并行, }
构 另( 目标, 关系 关系 = 关系.子, 目标 初化 = 目标.初化, 串 _f = __文件__, 整 _l = __行__ )
{目标 负载 = 初化;静 如 ( 关系 != 关系.独立 )本( 目标 值 ){负载 = 值;}静 如 ( 关系 == 关系.子)// 又 整 福; 福 f;// f.转换操作!(t)() == 转换(t) f目标 转换操作(目标)(){中 负载;}静 如 ( 关系 == 关系.子|| 关系 == 关系.并行 )别名 负载 本;静 如 ( 关系 == 关系.父 ) 的型( 本 ) 赋值操作( 目标 值 ){负载 = 值;中 本;}异 静 如 ( 关系 == 关系.子 )@禁止 空 赋值操作( 目标 值 );
}
动 o1 = 八进制!"755";
// 或甚至:
动 o2 = 八进制!755;
动 h1 = 16进制a!"中断";
动 b1 = 二元!1011011;
// 或甚至:
动 数字 = 基!(36, "4d6r7th2h7y");
元 比较(第一...)
{元 带(第二...){静 如 (第一.长度 != 第二.长度)枚 带 = 假;异 静 如 (第一.长度 == 0) // 比较结束枚 带 = 真;异 静 如 (!是(第一[0] == 第二[0]))枚 带 = 假;异枚 带 = 比较!(第一[1..$]).带!(第二[1..$]);}
}//使用:
单元测试
{别名 比较!(整, 双精, 串).带!(整, 双精, 符) C;静 断定(C == 假);
}
构 最小最大(T)
{T 最小;T 最大;T 值;别名 值 本;
}//最小最大
元 元组(名...)
如 (名.长度 && 都满足!(是个串字面, 名))
{动 元组(T...)(T 实参) 如 (T.长度 >= 名.长度){中 元组!(交错!(T).带!(名))(实参);}//
}
元 调试(别名 到测试, 串 文件 = __文件__, 大小型 行 = __行__)
{元 带(实参...){静 如 (是( 到测试!实参 ))别名 到测试!实参 带;异静 断定(0, "错误: " ~ 到!串(到测试)~ " 用实参调用: "~ 实参.的串);}
}
构 独特(T, 串 文件, 大小型 行)
{枚 大小型 l = 行;枚 串 f = 文件;T t;
}动 独特(T, 串 文件 = __文件__, 大小型 行 = __行__)(T t)
{中 独特!(T, 文件, 行)(t);
}//用于调试
d模板元编程笔记02相关推荐
- 闭关之 C++ 函数式编程笔记(四):monad 和 模板元编程
目录 第十章 monad 注意 10.1 仿函数并不是以前的仿函数 10.1.1 处理可选值 10.2 monad: 更强大的仿函数 10.3 基本的例子 10.4 range 与 monad 的嵌套 ...
- 模板元编程实现素数判定
模板元编程(英语:Template metaprogramming:缩写:TMP)是一种元编程技术,不夸张的说,这项技术开启了一种新的C++编程方式.编译器使用模板产生暂时性的源码,然后再和剩下的源码 ...
- 编程实现算术表达式求值_用魔法打败魔法:C++模板元编程实现的scheme元循环求值器...
本文使用 Zhihu On VSCode 创作并发布 [TOC] 前言 寒假时沉迷C++模板元编程,写了个简单的Scheme元循环求值器.可以用类似Scheme的语法写出这样的C++模板代码: _&l ...
- C++用模板元编程进行循环展开的性能测试
在网上看到一篇C++模板元编程的文章,里面提到可以用来做循环展开,文章地址如下: https://www.2cto.com/kf/20120... 然后在VS2015里测了一下,测试代码如下: tem ...
- C++模板元编程 入门简介
最近一直在看STL和Boost,源码里边好多涉及到模板元编程技术,简单了解一下,备忘(Boost Python中的涉及模板元的部分重点关注一下). 范例引入 // 主模板 template<in ...
- xpath里面if判断一个值不为空_现代C++之模板元编程(今天写个If与While)
现代C++之模板元编程(今天写个If与While) 0.导语 今天就放轻松,有可能代码写的看的很晦涩,自己多敲几遍即可,下面来进入正文,如何使用模板元编程实现IF与WHILE. 1.IF实现 我们想要 ...
- 现代C++模板元编程基础
元函数的基础介绍 C++的模板元编程是函数式编程,所以函数是一等公民.一切在编译期间执行的函数都可以称为元函数.元函数有struct和constexpr两种定义方式,前者是一直使用的,后者是C++11 ...
- C++ 模板元编程简介
文章目录 1.概述 2.模板元编程的作用 3.模板元编程的组成要素 4.模板元编程的控制逻辑 4.1 if 判断 4.2 循环展开 4.3 switch/case 分支 5.特性.策略与标签 6.小结 ...
- 跟我学c++高级篇——模板元编程之十一鸭子类型
一.鸭子类型 鸭子类型不是从c++中出现的,duck typing这种称呼在Python中比较多见.那么什么是鸭子类型呢?它是动态类型的一种风格,只要是对象的特征(其方法和属性集)和某个类型一致,就认 ...
最新文章
- ansible+powershell DSC 可以管理windows server了
- script 标签中async 属性和defer 属性作用以及区别?
- 数据挖掘-聚类分析(Python实现K-Means算法)
- php微信小程序获取用户信息,微信小程序获取openid及用户信息的方法
- 笔记:数据绑定表达式(一)
- Hibernate 查询数据
- genneratorConfig的记录 2021-04-18
- 关于服务限流的一些思考
- vb计算机二级操作题考试试题,计算机二级考试《VB》操作试题及答案2016
- R语言中ggplot Theme Assist安装使用教程
- 2020年了,Windows Me还能用吗?
- 从苏宁电器到卡巴斯基(后传)第04篇:还愿吾爱破解视频教程大赛
- 常用的锂电池充电芯片
- 联想一体机计算机桌面不显示,联想一体机关闭屏幕_联想一体机怎么关屏幕
- 房产管理系统有哪些领先技术的应用?
- 【OpenCV3】直线拟合--FitLine()函数详解
- 系统分析师学习笔记(十五)
- RocketMq的perm属性
- 解决IE浏览器下载文件,文件名乱码问题(浏览器历史介绍)
- c 语言密钥存储,在C中读取和写入rsa密钥到pem文件