【问题标题】:Examples of what D’s templates can be used forD 的模板可用于什么的示例
【发布时间】:2011-04-03 02:20:33
【问题描述】:

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

谁能举例说明 D 的元编程功能非常方便的情况?

【问题讨论】:

标签: metaprogramming d


【解决方案1】:

编译时函数执行的一个非常酷且实用的用法是在编译时生成代码,可能来自配置文件或脚本。

这是一个在编译时处理文件的简单示例。

ma​​in.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 放入文件中,在编译时将其读入以供使用,在运行时尝试其他一些值,然后将最好的值放回文件中。这样,您就可以逐渐提高性能,而无需手动执行任何操作。

【讨论】:

  • 还值得考虑imports 当前如何工作/应该与 rdmd 等中缓存行为的依赖指纹一起工作;导入的文件成为编译过程的额外依赖项,我认为这应该有助于散列结果。
【解决方案2】:

如果您想了解如何使用 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. 混合。这些允许您获取模板(模板混合)或编译时字符串(字符串混合)并将其评估为当前范围内的代码。字符串混合可以被认为有点像 eval 语句,只是字符串在编译时而不是在运行时被评估为代码。

  4. 编译时函数评估,或 CTFE,它允许在编译时评估满足特定条件的函数。 CTFE 的一个重要用途是,结合字符串混合,您可以在编译时将代码生成为字符串,然后在 mixin 语句出现的范围内将其评估为代码。有关这方面的示例,请参阅我最近检查到 Phobos 的 SVN 版本的 std.range.Lockstep 和 std.range.OutputRangeObject。

【讨论】:

    【解决方案3】:

    我所知道的最有趣的用法是 a library I wrote* 用于使用类型检查器来强制执行单位安全(即禁止将距离与时间相加,并在将米与英尺相加时提供正确的转换)。在 C++ 中可以并且已经完成了相同的操作,但是在编译时在 D 中执行此操作比在运行时执行此操作要困难一些。

    * 对不起这个无耻的插件。

    【讨论】:

      【解决方案4】:

      我并不精通元编程的目的。以下是我对 D 中的三个主要结构的看法。

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

      【讨论】:

      • CTFE 的部分价值在于生成与 mixins 一起使用的代码。例如,查看 SVN 版本的 Phobos 中的 std.range.Lockstep 或 std.range.OutputRangeObject。 (这两个都是我写的。)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-14
      • 1970-01-01
      • 1970-01-01
      • 2019-01-29
      相关资源
      最近更新 更多