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编译时解析器生成器.
浙公网安备 33010602011771号