可以使用D的模板的示例

时间:2010-08-24 10:24:28

标签: metaprogramming d

我听说D语言具有强大的元编程功能,可以在编译时执行函数。这听起来非常令人兴奋,但我发现很难想到没有它们很难实现的实际例子。

任何人都可以提供一些D的元编程功能非常方便的情况吗?

4 个答案:

答案 0 :(得分:21)

如果你想要如何使用D的元编程设备(CTFE,或编译时间函数评估,只是其中之一,甚至不是最重要的一个)的实际例子,那么D2标准库Phobos就是最好的选择。大部分代码都是由Andrei Alexandrescu编写的,他在C ++中发明了许多模板元编程技术,现在正在与Walter Bright合作设计和实现D。

要查看的最佳模块是std.rangestd.algorithm。它们几乎完全由模板组成,由Andrei设计,并且考虑到它们使用的元编程的数量,它们具有令人惊讶的可读性。我为这两个模块做出了重大贡献,并且在我开始学习时阅读的代码基本上就是我学到的。

所有代码都是根据(非常宽松的)Boost许可证授权的,并且可以在dsource.org上的Phobos Trac网站上viewed directly from your browser获得许可。

为了给你一个你所看到的路线图,D的元编程设施基本上分为4类:

  1. 模板,它们基​​本上类似于C ++模板,但增加了一些功能,例如static ifstatic assert,可变参数模板和约束,它们基本上都像概念但更简单。

  2. 编译时间反映/内省。这包括内置is()表达式和__traits,以及标准库模块std.traits。

  3. <强>混入即可。这些允许您获取模板(模板mixins)或编译时字符串(string mixins)并将其评估为当前范围中的代码。 String mixins可以被认为有点像eval语句,除了在编译时而不是在运行时将字符串计算为代码。

  4. 编译时间函数评估或 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中的三个主要结构的看法。

  • 编译时间功能评估是关于性能的。使编译器尽可能多地工作,以便在程序实际运行后完成更少的工作。
    • 就像构建素数缓存一样,如果你的程序经常使用它们。
  • 模板是关于消除算法重复。它不仅仅是通用编程,而且由于D具有CTFE,因此在与C ++相同的情况下不需要它。
  • Mixins 是关于能够在编译时生成添加到程序中的代码。它依赖于模板和CTFE之类的东西,但仍然是其他人无法提供的重要部分。

答案 3 :(得分:5)

我所知道的最实际有趣的用途是a library I wrote *,用于使用类型检查器来强制执行单位安全(即禁止添加距离到时间并在添加米时提供正确的转换英尺)。在C ++中也可以这样做,但在编译时在D中执行它比在运行时执行它要困难得多。

*对无耻的插件感到抱歉。