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
编译时解析器生成器.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现