d编译时函数式编程

原文

import std.range;

static assert(isInputRange!(uint[])); // true
static assert(isInputRange!string);  // true
static assert(!isInputRange!void);   // false

静断编译时断定.现在isInputRange类似C++概念.满足一定要求的模板.

template isInputRange(R)
{
    enum bool isInputRange = is(typeof(
    (inout int = 0)
    {
        R r = void;       //可定义区间对象
        if (r.empty) {}   // 三个函数
        r.popFront();     // 
        auto h = r.front; // 
    }));
}

我们可以这样来检查编译时接口实现:

struct CInterface
{
    string method1();
    bool method2();
}

struct A {}
static assert(isExpose!(A, CInterface));

我们来实现isExpose,并深入研究元编程.

计算阶乘

template factorial(uint n)
{
    private template inner(ulong acc, uint n)
    {
        static if(n == 0)enum inner = acc; 
        else
            enum inner = inner!(acc * n, n-1 ); 
    }
    enum factorial = inner!(1, n);
}
static assert(factorial!5 == 120);

C++可以直接普通前面加个常式就行了.
编写模板关键点是声明模板名相同的常量或别名,类似普通函数中的返回.此模式使用内部来组织尾递归.
可传递基本类型,类型,类型列表及最有趣的表达式列表的值到模板中.

template test(T...) {}

alias a1 = test!(ulong, float, double); 
alias a2 = test!("hi!", 23+42, [true, false], float);

上面是表达式列表.

template isExpose(Type, Interfaces...)
{
    private template isExposeSingle(Interface)
    {}
    enum isExpose = allSatisfy!(isExposeSingle, Interfaces);//allSatisfy,都满足.
}
template allSatisfy(alias F, T...)
{
    static if (T.length == 0)
    {
        enum allSatisfy = true;
    }
    else static if (T.length == 1)
    {
        enum allSatisfy = F!(T[0]);
    }
    else
    {
        enum allSatisfy =
            allSatisfy!(F, T[ 0  .. $/2]) &&
            allSatisfy!(F, T[$/2 ..  $ ]);
        // 二叉树.而非下面挨个处理.
        // enum allSatisfy = F!(T[0]) && allSatisfy!(F, T[1 ..  $ ]);
    }
}

别名关键字声明,按名字传递.创建列表:

template List(T...)
{
    alias List = T;
}

编译器找出接口成员(方法和字段)列表.

template getMembers(T)
{
    alias getMembers = List!(__traits(allMembers, T));
}

接口元素名匹配但类型不匹配被检查类型.要附加元素类型到名称上,组织简单管道,但首先需要些辅助模板.静重复.

template staticReplicate(TS...)
{
    static if(is(TS[0]))
        alias T = TS[0];
    else 
        enum T = TS[0];
        
    enum n = TS[1];
    
    static if(n > 0)
    {
        alias staticReplicate = List!(T, staticReplicate!(T, n-1));
    }
    else
    {
        alias staticReplicate = List!();
    }
} 
/// Example
unittest
{    
    template isBool(T)
    {
        enum isBool = is(T == bool);
    }
    
    static assert(allSatisfy!(isBool, staticReplicate!(bool, 2))); 
    static assert([staticReplicate!("42", 3)] == ["42", "42", "42"]);
}

两个两个映射:

template staticMap2(alias F, T...)
{
    static assert(T.length % 2 == 0);
    
    static if (T.length < 2)
    {
        alias staticMap2 = List!();
    }
    else static if (T.length == 2)
    {
        alias staticMap2 = List!(F!(T[0], T[1]));
    }
    else
    {
        alias staticMap2 = List!(F!(T[0], T[1]), staticMap2!(F, T[2  .. $]));
    }
}
/// 示例
unittest
{
    template Test(T...)
    {
        enum Test = T[0] && T[1];
    }
    
    static assert([staticMap2!(Test, true, true, true, false)] == [true, false]);
}

静态折叠:

template staticFold(alias F, T...)
{
    static if(T.length == 0) // 无效输入
    {
        alias staticFold = List!(); 
    }
    else static if(T.length == 1)
    {
        static if(is(T[0]))
            alias staticFold = T[0];
        else
            enum staticFold = T[0];
    }
    else 
    {
        alias staticFold = staticFold!(F, F!(T[0], T[1]), T[2 .. $]);
    }
}

多个列表显式展开:

template StrictList(T...)
{
     alias expand = T;
}

StrictList!(T,U).expand时,返回T,U的列表.
静态拉链:

template staticRobin(SF...)
{
    private template minimum(T...)
    {
        enum length = T[1].expand.length;
        enum minimum = T[0] > length ? length : T[0];
    }//最小
    enum minLength = staticFold!(minimum, size_t.max, SF);
    private template robin(ulong i)
    {
        private template takeByIndex(alias T)
        {
            static if(is(T.expand[i]))
                alias takeByIndex = T.expand[i];
            else
                enum takeByIndex = T.expand[i];
        }
        
        static if(i >= minLength)
        {
            alias robin = List!();
        }
        else
        {
            alias robin = List!(staticMap!(takeByIndex, SF), robin!(i+1));
        }
    }
    alias staticRobin = robin!0; 
}
/// 示例.
unittest
{
    alias test = staticRobin!(StrictList!(int, int, int), StrictList!(float, float));
    static assert(is(test == List!(int, float, int, float)));
    
    alias test2 = staticRobin!(StrictList!(1, 2), StrictList!(3, 4, 5), StrictList!(6, 7));
    static assert([test2]== [1, 3, 6, 2, 4, 7]);
}

总思路:1个方法+接口,然后用绑定类型赋值接口.然后用都满足来检查.

alias intMembers = StrictList!(getMembers!Interface); //取接口成员
alias intTypes = StrictList!(staticReplicate!(Interface, intMembers.expand.length));
//重复数.
alias pairs = staticMap2!(bindType, staticRobin!(intTypes, intMembers));

private template bindType(Base, string T)
{
    alias bindType = List!(typeof(mixin(Base.stringof ~ "." ~ T)), T);
    //绑定类型.取接口元素类型.
    //取得生成表达式的类型.
}

检查成员:

template checkMember(MemberType, string MemberName)
{
    static if(hasMember!(Type, MemberName))
    {
        enum checkMember = is(typeof(mixin(Type.stringof ~ "." ~ MemberName)) == MemberType);//类型是否相同.
    }
    else
    {
        enum checkMember = false;
    }
}

enum isExposeSingle = allSatisfy2!(checkMember, pairs);

然后,组装起来:

template isExpose(Type, Interfaces...)
{
    private template getMembers(T)
    {
        alias getMembers = List!(__traits(allMembers, T));
    }
    
    private template isExposeSingle(Interface)
    {
        alias intMembers = StrictList!(getMembers!Interface); 
        alias intTypes = StrictList!(staticReplicate!(Interface, intMembers.expand.length));
        alias pairs = staticMap2!(bindType, staticRobin!(intTypes, intMembers));
                
        private template bindType(Base, string T)
        {
            alias bindType = List!(typeof(mixin(Base.stringof ~ "." ~ T)), T);
        }
        
        template checkMember(MemberType, string MemberName)
        {
            static if(hasMember!(Type, MemberName))
            {
                enum checkMember = is(typeof(mixin(Type.stringof ~ "." ~ MemberName)) == MemberType);
            }
            else
            {
                enum checkMember = false;
            }
        }
        
        enum isExposeSingle = allSatisfy2!(checkMember, pairs); 
    }
    
    enum isExpose = allSatisfy!(isExposeSingle, Interfaces);//所有接口都满足条件.
}

使用示例:

struct CITest1
{
    string a;
    string meth1();
    bool meth2();
}

struct CITest2
{
    bool delegate(string) meth3();
}

struct CITest3
{
    bool meth1();
}

struct Test1
{
    string meth1() {return "";}
    bool meth2() {return true;}
    
    string a;
    
    bool delegate(string) meth3() { return (string) {return true;}; };
}

static assert(isExpose!(Test1, CITest1, CITest2));
static assert(!isExpose!(Test1, CITest3));

基于强大元编程,可编写方便的DSL或模板来摆脱样板代码.实践中很好例子是pegged编译时解析器生成器.

posted @   zjh6  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示