d模板元编程笔记03

986 篇文章 1 订阅
48 篇文章 0 订阅

编译时工具,
编译时元编程:串插件,编译时求值,特征,他们可互操作,模板化编译时函数可返回串,并再次插入模板中,编译时求值函数可作模板参数用来模板化.
串插件在编译前安放,代码按串操作,注入后,就是真正的代码了.这就是.
插件(代码串),别忘了括号,串插件是编译时工具.串也必须是编译时生成的

插件("整 i = 3;"); //两个分号
i++;
断定(i == 4);
模块 用我的结构1;
导入 我的结构1;

插件(我的构!"第一");  // 创建 a 新 类型 调用 第一 (a 构)
插件(我的构!"第二"); // 和 另一 一 调用 第二

空 主()
{
    // "第一" 代码 是 注入 右 那儿, 在 模块 '我的'.
    第一 f1, f2;
    第二 s1;

    断定(( 的型(f1) == 第一));
}

常量折叠有意思.d中,可编译时连接.这里串插件模板合作.模板可用作模板参数,模板也可编译时生成串.

元 我的构(串 名)
{
    枚 串 我的构 = "构 " ~~ " { "
     ~ "/+ 一些代码 +/"
     ~ " }";
}

//   "构 第一 { /+ 一些代码 +/ }"
//
模块 我的结构2;

元 我的构(串 名)
{
    别名 我的构实现!().结果 我的构;
}

元 我的构实现(串 名)
{
    枚 串 代码 = 
            "构 " ~~ " { "
             ~ "/+ 一些 代码 +/"
             ~ " }";
    插件(代码);
    插件("别名 " ~~ " 结果;");
}
模块 用我的结构2;
导入 我的结构2;//这样使用

我的构!"第一" f1, f2;
我的构!"第二" s1;

比自动补全还强.几个插件可以连起来.无尽的简写啊.可以将常用操作直接简化在宏层面.

元 我的构(串 名)
{
    别名 我的构实现!().结果 我的构;
}

元 我的构实现(串 名)
{
插件("构 " ~~ " {"
    ~ "/* 一些代码 */"
    ~ " }\n"
    ~ "别名 " ~~ " 结果;");
}

没必要分开实现,多此一举.
注意串是在包含我的构工具模块生成的.但第一第二是在插件!()点定义,注意在放插件(..)的地方实例化.如果在不同模块放插件(...),相同参数,则名字相同,但他们不同.不同模块,定义相同构.类似复制了相同结构.
为了不同模块有相同构类型,必须在模板模块生成构
这样,第一实现中生成,并通过别名(特定别名通过串插件生成)暴露,除了多了个别名,感觉没啥区别.

枚 取置 { no,}S(取置 取置 = 取置.no, T)
{
    枚 优先 = "私 T 值;\n"
              ~ "T 取() @属性 { 中 值;}\n"
              ~ "空 置(T _值) { 值 = _值;}";

    枚 公开 = "T 值;";

    插件( (取置 == 取置.) ? 优先 : 公开);
}

编译时?:,等价于静如

空 主()
{
    S!(取置.,) gs;
    gs.(1);
    断定( gs.== 1);
}
构 S!(取置.,)
{
    私 整 值;
    整 取() @属性 { 中 值;}
    空 置(整 _值) {= _值;}
}

你可以先弄些带占位符的代码,然后用类型/名来替代.最后,串插件->宏.可以测试下静如看有无限制.
转义字符串,可用q{},其实用文件最好.

编估(编译时求值函数)

__ctfe

导入 标.转换;

枚 取置 { no,}

串 优先(串 类型, 串 索引)
{"私 "~类型~" 值"~索引~";\n"
  ~ 类型~" 取"~索引~"() @属性 { 中 值"~索引~";}\n"
  ~ "空 置"~索引~"("~类型~" _值) { 值"~索引~" = _值;}";
}

串 公开(串 类型, 串 索引)
{
    中 类型 ~ "值" ~ 索引 ~ ";";
}

串 生成s(取置 取置 = 取置.no, T...)()
{
    串 结果;
    每一(索引, 类型; T)
        静 如 (取置 == 取置.)
             结果 ~= 优先(类型.的串,!(索引));
        异
            结果 ~= 公开(类型.的串,!(索引));
    中 结果;
}S(取置 取置 = 取置.no, T...)
{
    插件(生成s!(取置,T));
}

空 主()
{
    S!(取置.,,,) gs;

/* 生成:
构 S!(取置.是, 整, 串, 整)
{
    私 整 值0;
    整 取0() @属性 { 中 值0;}
    空 置0(整 _值) { 值0 = _值;}

    私 串 值1;
    串 取1() @属性 { 中 值1;}
    空 置1(串 _值) { 值1 = _值;}

    私 整 值2;
    整 取2() @属性 { 中 值2;}
    空 置2(整 _值) { 值2 = _值;}
}
*/

    gs.1("abc");
    断定(gs.1 == "abc");
}
导入 插补串;

别名 插入!"构 #0 { #1 值; #0[#2] 子;}" 造树;

枚 串 整树 = 造树("整树", "整", 2);
枚 串 双树 = 造树("双树", "双精", "");

静 断定(整树
          == "构 整树 { 整 值; 整树[2] 子;}");
静 断定(双树
          == "构 双树 { 双精 值; 双树[] 子;}");
模块 插补串;
导入 标.转换;

元 插入(串 代码)
{
    串 插入(实参...)(实参 实参) {[] 串化;
        每一(索引,; 实参) 串化 ~=!();

        串 结果;
        整 i;
        整 零 =!('0');(i < 代码.长度) {(代码[i] == '#') {
                整 j = 1;
                整 索引;(i+j < 代码.长度
                    &&!(代码[i+j])->= 0
                    &&!(代码[i+j])-<= 9)
                {
                    索引 = 索引*10 +!(代码[i+j])-;
                    ++j;
                }

                结果 ~= 串化[索引];
                i += j;
            }{
                结果 ~= 代码[i];
                ++i;
            }
        }

        中 结果;
    }
}

简单插值字符串,都是在玩代码串,一元串/二元串

极 是小写(符 c) {
    中 c >= 'a' && c <= 'z';
}

极 是小写(符 c) {
    中 c >= 'A' && c <= 'Z';
}

极 是非字母(符 c) {!是小写(c) && !是小写(c);
}

整 字母数(符 c) {
    中 到!(c) -!('a') + 1;
}

整 数量(串 s) {(s.长度 == 0)0;

    整 数量;
    串 内边距 = " " ~ s ~ " ";
    每一(i, c; 内边距[0..$-2])(是小写(内边距[i+1])
         && 是非字母(内边距[i])
         && 是非字母(内边距[i+2]))
            数量 = 字母数(内边距[i+1]) > 数量 ?
                    字母数(内边距[i+1])
                  : 数量;
    中 数量;
}

串 元类型(整 算法) {(算法 == 0)"";(算法 == 1)"A";

    串 结果;
    每一(i; 0..算法)
        结果 ~= "大写26字母"[i] ~ ", ";

    中 结果[0..$-2];
}

串 形参(整 算法) {(算法 == 0)"";(算法 == 1)"A a";

    串 结果;
    每一(i; 0..算法)
        结果 ~= "大写26字母"[i]
               ~ " " ~ "字母26"[i]
               ~ ", ";

    中 结果[0..$-2];
}

串 n元函数体(串 代码, 整 算法) {
    中 插入!"动 引用 n数组函数(#0)(#1) { 中 #2;}"
                      (元类型(算法), 形参(算法), 代码);
}

元 n数组函数(串 代码, 整 算法 = 数量(代码))
{
    插件(n元函数体(代码, 算法));
}
整 对数上圆整2(整 n)
{
    整 i;((n & (n-1)) == 0) i = -1;(n > 0) { ++i; n/= 2;}
    中 i;
}

/**
 * 给定n长度, 返回排序网络的索引对数组
 */[2][] 排序网络(整 n)//像不像C代码
{[2][] 网络;
    动 t = 对数上圆整2(n);
    动 p = 1 << (t-1);(p > 0)
    {
        动 q = 1 << (t-1);
        动 r = 0;
        动 d = p;(d > 0)
        {(整 i = 0; i<=(n-d-1); ++i)
            {(r == (i & p)) 网络 ~= [i, i+d];
            }
            d = q-p;
            q /= 2;
            r = p;
        }
        p /= 2;
    }
    中 网络;
}
导入 插补串;
导入 排序网络;

串 构建排序代码(大小型 l)()
{
    枚 网络 = 排序网络!(l);
    串 结果;
    每一(元素; 网络) 结果 ~=
        插入!(
        "t1 = 输入[#0];
         t2 = 输入[#1];(!二元函数!判词(t1, t2))
         {
             动 临时 = t2;
             输入[#1] = t1;
             输入[#0] = 临时;
         }\n")(元素[0], 元素[1]);
    中 结果;
}
模块 排序网络;
导入 标.区间;
导入 标.函数;
导入 标.异常;
导入 构建排序代码;
导入 插补串;

元 排序网络(大小型 l)
{
    插件(
插入!(//这个插入很重要.
    "空 排序网络(别名 判词 = \"a < b\", R)(引用 R 输入)(是随机访问区间!R)
     {
         强制(输入.长度 >= #,
                 \"调用 排序网络!# 带 a 区间 of 较少 比 # 元素\");
          元素类型!R t1, t2;")(l)
      ~ 构建排序代码!(l)
 ~ "}");
}
//某地代码
别名 排序网络!32 排序32;//两层控制.

//另一个地方
排序32(我的数组);
排序32!"a > b"(我的数组);//判词.

想要预生成排序网络的模板.判词用来表明如何比较.
插件在模板中,其实(两个模板参,可放在一起),不用这么折腾.如果,你对数据排序规律有了解,则可编译时根据情况生成不同运行代码.
特征类似,是编译时自省(自我检查).可在符号,表达式,类型自省.类似c++类型特征.

isArithmetic
isAssociativeArray
isFloating
isIntegral
isScalar
isStaticArray
isUnsigned
isAbstractClass
isFinalClass
isVirtualFunction
isAbstractFunction
isFinalFunction
isStaticFunction
isRef
isOut
isLazy
hasMember
isSame
compiles

特征获取类型的新信息更有意思.标识符给你一个符号串

元 的名(别名 a)
{
    枚 串 名 = a.的串; // 枚: 清单常量
// 编译时
}
整 福(整 i, 整 j) { 中 i+j;}

动 名 = 的名!;//错,必须用2个参数
元 的名(别名 a)
{
    枚 串 的名 = __特征(标识符, a);
}//特征

单元测试
{
    整 福(整 i, 整 j) { 中 i+j;}
    枚 名 = 的名!; //可用

    断定(== "福");
}
导入 的名;

枚 名2 = 的名!(的名); // "的名(别名 a)"
枚 名3 = 的名!(.构造类型); //"构造类型"

模板名,类名,模块都适用.
__traits(getMember, name, "member")直接让你访问name.member,这是真实成员,任何带成员D构都可以这样.为什么聚集可用名字直接调用而成员需要一个串,是因为聚集是个符号(本身就存在),而成员名不在聚集外,甚至引用到其他不相关构.
聚集带成员构,(构,类,接口,模板)都是聚集,模板是个命名的参数化域.所以所有特征模板也管用.模块不是一等公民,但也是聚集体.
__traits(allMembers, aggregate),返回聚集体的所有成员(串字面量的元组).对,也包括父类的成员
.的大小未在里面,元组数组强点,可在编译时迭代

类 我的类
{
    整 i;() { i = 0;}(整 j) { i = j;}
    ~() { }

    空 福() { ++i;}
    整 福(整 j) { 中 i+j;}
}

空 主()
{
    枚 我的成员 = [__特征(所有成员, 我的类)];//变成数组.

    断定(我的成员 == ["i", "__构造器", "__析构器", "福", "至串","至哈希", "比较操作", "等于操作", "监视器", "工厂"]);
    //标准类,重载只算一次
}

取成员字段的好方法.后面可直接用getMember进一步

类 我的类(T)
{
    T 字段;
}

静 断定([__特征(所有成员, 我的类)] == ["我的类"]);

元 我的类(T)//这才是真相.同名的只一个.
{
    类 我的类
    {
        T 字段;
    }
}
模块 所有成员元2;
导入 所有成员元;

静 断定([__特征(所有成员, 我的类!)]//实例化
           == ["字段", "至串", "至哈希", "比较操作","等于操作", "监视器", "工厂"]);
模块 自省元;

元 临时(A, B)
{
    A a;
    B 福(A a, B b) { 中 b;}
    整 i;
    别名 A    类型;
    别名 A[B] AA类型;
}

静 断定([__特征(所有成员, 临时)]
           == ["a", "福", "i", "类型", "AA类型"]);
静 断定([__特征(所有成员, 临时!(双精,))]
           == ["a","福", "i", "类型", "AA类型"]);
//参数不同,但成员一样.
模块 所有成员模块;
导入 标.算法;
导入 标.编译器;

// 大的名字列表 
枚 算法 = [__特征(所有成员,.算法)];
// 稍微短点
枚 编译器 = [__特征(所有成员,.编译器)];

空 主()
{
    断定(编译器 == ["对象", "名", "供应商", "供应商", "主要版本", "小版本", "d主要", "次d"]);
}

构类函数模板只是语法糖,模板参数不一样,但成员一样,说明这只是一个命名参数化的域.对构/模板也是如此.
import pack.mod;导入mod符号.
import mod;什么都没导入.可能有模板递归遍历成员,找模板并继承递归下去,得到一个完整的导入树,但std不这样,因为没有成员.
检查模块,用串插件生成某种类型,如果用户在自己模块中用可能会冲突,给个类名,给我其所在的层次.类型元组参数即使重载时,也给了一个函数的参数类型元组.所以用模块名得到所有函数列表,并对每一个取其参数元组.
derivedMembers,只得到子类自己的成员,不包括父的
getOverloads,取重载.__traits(getOverloads, name, "member")某个成员的所有本地重载.本地表示不含父类重载.
给定聚实名/聚集实体,成员名作为串.getOverloads+类型+实例(得到所有重载元组),用__构造器,你可直接访问类型构造器的重载,有时,他们很方便.

构 成员(串 n, T)
{
    枚 名 = n; // 外部访问
    别名 T 类型;
}
模块 造成员;
公 导入 成员;
导入 的名;

元 造成员(别名 成员)
{
    插件( "别名 成员!(\""
         ~ 的名!成员
         ~ "\", 的型(成员)) 造成员;");
}//外部访问

元 造命名成员(串 名)
{
    元 造命名成员(别名 成员)
    {
        插件( "别名 成员!(\""
             ~~ "\", 的型(成员)) 造命名成员;");
    }//~名~.
}//有成员后,分发关联成员模板
导入 标.类型元组;
导入 造成员;

元 重载(别名 a, 串 成员)
{
    别名 静映射!(造成员,__特征(取重载,a,成员))重载;
}
模块 我的类;

类 我的类
{
    整 i; // 字段
    别名 i j; // 符号 别名

    别名 整 整; // 类型 别名

    构 内部 {} // 内部 类型

    元 临时(T) { 别名 T 临时;} // 元() { i = 0;} // 构造器 #1(整 j) { i = j;} // 构造器 #2
    ~() { }

    空 福(整 j) { ++i;} // 福 重载 #1
    整 福(整 j, 整 k = 0) { 中 i+j;} // 福 重载 #2

    别名 福 条; // 符号别名

    单元测试
    {
        整 i;
    }
}
模块 用重载1;
导入 标.标io;
导入 重载1;
导入 我的类;

空 主()
{
    别名 重载!(我的类, "福") o;

    /*
    打印:
    福,类型: 空(整 j)
    福,类型: 整(整 j, 整 k = 0)
    */
    每一(元素; o)
        写行(元素., ",类型: ", 元素.类型.的串);
}

还要加强名字,

元 重载(别名 a, 串 成员)
{
    // a.成员是方法
    静 如 (__特征(编译, __特征(取重载, a, 成员))
        && __特征(取重载, a, 成员).长度 > 0)
        别名 静映射!(造命名成员!(成员), __特征(取重载, a, 成员)) 重载;// 字段或别名
    // a.成员是字段, 或符号别名
        静 如 ((的型(__特征(取成员, a, 成员))))
            插件( "别名 成员!(\""~ 成员
                 ~ "\", 的型(__特征(取成员, a, 成员))) 重载;");
    // a.成员是类型别名
    异 静 如 (插件( "是(成员!(\""~ 成员
                         ~ "\", __特征(取成员, a, 成员)))"))
        插件( "别名 成员!(\""~ 成员
             ~ "\", __特征(取成员, a, 成员)) 重载;");
    // a.成员是元
    异
        插件( "别名 成员!(\""
             ~ 成员
             ~ "\", 空) 重载;");
}

重载时要小心,当然也可能最新版本改进了.
给出字段,方法,类型别名,符号别名,模板名时来处理各种成员,最后是取它.

元 取重载(别名 a)
{
    元 取重载(串 成员)
    {
        别名 重载!(a, 成员) 取重载;
    }
}

元 所有成员(别名 a)
{
    别名 静映射!(取重载!(a),__特征(所有成员, a)) 所有成员;
}

两阶段构造.其实还是啰嗦了点.

模块 用所有成员2;
导入 标.类型元组;
导入 标.标io;
导入 我的类;
导入 所有成员;

空 主()
{
    别名 所有成员!(我的类) O;
    写行(O.的串);

    每一(o; O)写行(o., ",类型:" ~ o.类型.的串);
    /*
    打印:
    i,具类型: 整
    j,具类型: 整
    整,具类型: 整
    (...)
    __构造器, 具类型: 我的类()
    __构造器, 具类型: 我的类(整 j)
    (...)
    福, 具类型: 空(整 j)
    福, 具类型: 整(整 j, 整 k = 0)
    (...)
    */
}

可以将所有成员放进哈希表/多态关联列表中,然后,用来运行时反射.像这样:(a.send("someMethod", args), a.setInstanceVariable("i",5))
聚集成员列,从而很容易取接口列表,来检查指定成员是否包含整个接口列表.检查是否都实现了的意思.

模块 实现;
导入 标.类型元组;
导入 所有成员;

//检查a是否实现所有I接口
元 实现(别名 a, I)((I == 接口))
{
    别名 实现实现!(a, 所有成员!I) 实现;
}

元 实现实现(别名 a,...)
{
    静 如 (.长度 == 0)
        枚 实现实现 =;
    异 静 如 (的静索引!([0], 所有成员!a) == -1)
        枚 实现实现 =;
    异
        枚 实现实现 = 实现实现!(a,[1..$]);
}

接口 I
{
    整 福(整 i);
    空 福();

    串 至串();
}

类 坏
{
    空 福(整 i) {}
}//只一个

构 好
{
    整 字段;

    整 福(整 i) { 中 i;}
    空 福() { 字段 = 1;}

    串 至串() {"我是个好构!";}
}

单元测试
{
    断定( 实现!(, I));
    断定(!实现!(, I));
}

getVirtualFunctions,给出类方法虚重载,可以练习找出所有字段,覆盖的重载,
__traits(parent, symbol)找父,找父域.

模块 c类;
导入 的名;

类 C
{
    整 i;
    整 福(整 j)
    {
        整 k; // k 是 "c类.C.福.k"
        断定(的名!(__特征(, k)) == "福");
        中 i+k;
    }
}

并不是类层次的父.到达顶级,返回模块名(危险,因为模块自身没有).

模块 父;
导入 的名;
导入 c类;

// C是指(c类.C)
静 断定(的名!(__特征(, C)) == "c类");

空 主()
{
    动 c =C(); // c 是 "父.主.c"
    断定(的名!(__特征(, c)) == "主");
    断定(的名!(__特征(, c.i)) == "C");
    c.(1);
}

取上一层的域.

导入 的名;

元 全名(别名 a)
{
    // 有父不?
    静 如 (__特征(编译, __特征(, a)))
    // 有,取名并递归
        枚 全名 = 全名!(__特征(, a))
                 ~  "." ~ 的名!(a);
    // 无,是个模块,并终止
    异
        枚 全名 = 的名!a;
}
模块 用全名;
导入 全名;
导入 c类;

空 主()
{
    动 c =C();
    断定(全名!c == "用全名.主.c");
    断定(全名!(c.) == "c类.C.福"); //两例相同 
    断定(全名!(C.) == "c类.C.福");
}

注意c.福不是usingqualifiedname.main.c.foo
处理串插件和插件模板时,要知道你注入的
建一个局部变量,取其父.即可确定插件的域,然后暴露域的名(叫他域名),相应取的模板叫取域名.

公 导入 全名;

插件 元 取区域名()
{
    枚 区域名 = 全名!(__特征(, 区域名));
}
模块 用区域名;
导入 标.标io;
导入 区域名;

类 C
{
    插件 取区域名; // 1,这里

    整 i;
    整 福(整 j)
    {
        整 k;
        插件 取区域名; // 2,在这里
        写行(区域名);
        中 i+k;
    }
}

空 主()
{
    动 c =C();
    写行(c.区域名); // "测试.C" (1)
    c.(1);// "测试.C.福" (2)

    插件 取区域名; // 3
    写行(区域名); // "测试.主" (3)
}

声明本域名,并在同一表达式取其父,这没问题.最新的现在不能循环引用了.
对表达式元组也有用.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值