D语言的模板使用非常方便灵活,受够了C++模板编写之苦的同学们可以感受一下D语言的模板,下面先展示一个D语言编写的多分派委托类,在我的旧BLOG上曾经写过一个C++版本的,整个过程感觉非常痛苦。。。
闲话少说,请看代码:
import std.stdio;
template DelegateHandlers(HandlerType, FunctionType)
{
HandlerType[] handlers;
FunctionType[] functions;
void opAddAssign(HandlerType h)
{
handlers.length = handlers.length + 1;
handlers[length-1] = h;
}
void opAddAssign(FunctionType f)
{
functions.length = functions.length + 1;
functions[length-1] = f;
}
}
template Delegate(Ret)
{
class Delegate
{
alias Ret delegate () HandlerType;
alias Ret function () FunctionType;
mixin DelegateHandlers!(HandlerType, FunctionType);
static if(is(Ret: void))
{
void opCall ()
{
foreach (HandlerType handler; handlers)
handler ();
foreach (FunctionType _function; functions)
_function ();
}
}
else
{
Ret opCall ()
{
Ret ret;
foreach (HandlerType handler; handlers)
ret = handler ();
foreach (FunctionType _function; functions)
ret = _function ();
return ret;
}
}
}
}
template Delegate(Ret, Arg1)
{
class Delegate
{
alias Ret delegate (Arg1) HandlerType;
alias Ret function (Arg1) FunctionType;
mixin DelegateHandlers!(HandlerType, FunctionType);
static if(is(Ret: void))
{
void opCall (Arg1 a1)
{
foreach (HandlerType handler; handlers)
handler (a1);
foreach (FunctionType _function; functions)
_function (a1);
}
}
else
{
Ret opCall (Arg1 a1)
{
Ret ret;
foreach (HandlerType handler; handlers)
ret = handler (a1);
foreach (FunctionType _function; functions)
ret = _function (a1);
return ret;
}
}
}
}
class Test
{
void test ()
{
writefln ("Test.test");
}
int test1 ()
{
writefln ("Test.test1");
return 1;
}
void test2(int v)
{
writefln ("Test.test2");
}
int test3(int v)
{
writefln ("Test.test3");
return 7;
}
}
void test_func ()
{
writefln ("test_func");
}
int test_func1 ()
{
writefln ("test_func1");
return 2;
}
void test_func2(int v)
{
writefln ("test_func2");
}
int test_func3(int v)
{
writefln ("test_func3");
return 9;
}
void main()
{
Test t = new Test;
alias Delegate!(void) DDD;
DDD d = new DDD;
d += &t.test;
d += &test_func;
d ();
alias Delegate!(int) DDD1;
DDD1 d1 = new DDD1;
d1 += &t.test1;
d1 += &test_func1;
int a = d1 ();
assert (a == 2);
alias Delegate!(void, int) DDD2;
DDD2 d2 = new DDD2;
d2 += &t.test2;
d2 += &test_func2;
d2 (1);
alias Delegate!(int, int) DDD3;
DDD3 d3 = new DDD3;
d3 += &t.test3;
d3 += &test_func3;
int b = d3 (2);
assert (b == 9);
}
非常干净,非常简洁,不是吗?这个只花了我10分钟时间来写。。。
D语言的委托非常高效,有兴趣的可以测试一下通过委托和直接调用之间的性能差别。上面这个自己实现的多分派委托类,效率也非常高,我的测试结果是对于性能的影响几乎可以忽略。想起那个历尽千辛万苦实现的C++多分派委托类,实现复杂、调试费时、运行效率还很低,每每一想到这心里那个难受啊。。。。
再来看一下D语言强大的静态检查机制:
template XXX (int v)
{
int n = v;
static assert (v > 3);
}
void main ()
{
int n;
n = XXX!(4).n; // OK
n = XXX!(3).n; // 编译错误
}
同样很漂亮。
如果你觉得提示信息不够友好,可以修改为:
template XXX (int v)
{
int n = v;
static if (v <= 3)
pragma (msg, "template value must > 3");
static assert (v > 3);
}
这是编译时的错误提示:
Compiling test.d ...
template value must > 3
D:\workspace\dace\test.d(94): static assert (3 > 3) is false
D:\workspace\dace\test.d(173): template instance test.XXX!(3) error instantiating
我想以后有可能会扩充pragma,支持错误输出,这样就不用写重复的语句了,可以简化成这样:
template XXX (int v)
{
int n = v;
static if (v <= 3)
pragma (error, "template value must > 3");
}
这样看起来更好。不过目前有很多重要特性要实现,这种玩意可能要很久以后才会加入了。