我听说D语言具有强大的元编程功能,可以在编译时执行函数。这听起来非常令人兴奋,但我发现很难想到没有它们很难实现的实际例子。
任何人都可以提供一些D的元编程功能非常方便的情况吗?
答案 0 :(得分:21)
如果你想要如何使用D的元编程设备(CTFE,或编译时间函数评估,只是其中之一,甚至不是最重要的一个)的实际例子,那么D2标准库Phobos就是最好的选择。大部分代码都是由Andrei Alexandrescu编写的,他在C ++中发明了许多模板元编程技术,现在正在与Walter Bright合作设计和实现D。
要查看的最佳模块是std.range
和std.algorithm
。它们几乎完全由模板组成,由Andrei设计,并且考虑到它们使用的元编程的数量,它们具有令人惊讶的可读性。我为这两个模块做出了重大贡献,并且在我开始学习时阅读的代码基本上就是我学到的。
所有代码都是根据(非常宽松的)Boost许可证授权的,并且可以在dsource.org上的Phobos Trac网站上viewed directly from your browser获得许可。
为了给你一个你所看到的路线图,D的元编程设施基本上分为4类:
模板,它们基本上类似于C ++模板,但增加了一些功能,例如static if
,static assert
,可变参数模板和约束,它们基本上都像概念但更简单。
编译时间反映/内省。这包括内置is()
表达式和__traits
,以及标准库模块std.traits。
<强>混入即可。这些允许您获取模板(模板mixins)或编译时字符串(string mixins)并将其评估为当前范围中的代码。 String mixins可以被认为有点像eval语句,除了在编译时而不是在运行时将字符串计算为代码。
编译时间函数评估或 CTFE ,它允许在编译时评估满足特定条件的函数。 CTFE的一个重要用途是,结合字符串mixins,您可以在编译时将代码生成为字符串,然后将其作为mixin
语句出现的范围内的代码进行评估。有关此示例,请参阅std.range.Lockstep和std.range.OutputRangeObject,我最近检查了Phobos的SVN版本。
答案 1 :(得分:21)
编译时函数执行的一个非常酷的实际用法是在编译时生成代码,可能来自配置文件或脚本。
这是一个在编译时处理文件的简单示例。
<强> main.d 强>
string make_ints(string s)
{
string ret = "";
foreach (varname; split(s))
ret ~= "int " ~ varname ~ "; ";
return ret;
}
void main()
{
mixin(make_ints(import("script")));
foo = 1;
bar = 2;
xyz = 3;
}
<强>脚本强>
foo bar xyz
在编译时,将读取文件“script”,在空格处拆分,然后make_ints将int foo; int bar; int xyz;
直接返回到D代码中,准备好使用这些变量。
虽然这是一个无用的示例,但您可以很容易地看到如何使用它来从配置文件中读取值(可能是缓存大小的值,或类似的值)。游戏可以利用它来从脚本生成原始D代码,这对性能很有帮助(通常游戏使用解释代码进行脚本编写,并且在性能方面受到影响)。
您也可以将其用于自动性能调整。假设您有一些常量X,可以通过各种方式调整以影响性能,但您不知道X的哪个值会为您提供最佳性能。您可以将X放在一个文件中,在编译时读取它以供使用,在运行时尝试一些其他值并将最好的值放回到文件中。这样,您可以逐步提高性能而无需手动执行任何操作。
答案 2 :(得分:5)
我不太熟悉元编程的目的。以下是我对D中的三个主要结构的看法。
答案 3 :(得分:5)
我所知道的最实际有趣的用途是a library I wrote *
,用于使用类型检查器来强制执行单位安全(即禁止添加距离到时间并在添加米时提供正确的转换英尺)。在C ++中也可以这样做,但在编译时在D中执行它比在运行时执行它要困难得多。
*
对无耻的插件感到抱歉。