你用 D 编程语言做过或见过的最酷的、实用的元编程技巧是什么?有点实用意味着排除,例如,编译时光线追踪器。
12 回答
任意精度类型它在编译时生成 ASM 代码(在编译器之前)
Scrapple 工具中的 DParse 是一个模板化的解析器生成器。然而,ldc 是唯一一个具有正常运行的编译时 GC 的 D 编译器(但即便如此,它也有一些奇怪的随机崩溃)。我玩了一点,你可以做一些有趣的事情,比如配置文件解析和其他东西,但是在编译时 GC 完全运行之前你不能做大事。
D/Objective-C 桥使用模板让您在 D 中操作 Cocoa 对象。
我最喜欢的是来自 tools.base 的 ElemType 和 KeyType:
template ElemType(T) {
alias typeof((function() {
foreach (elem; Init!(T)) return elem; assert(false);
})()) ElemType;
}
template KeyType(T) {
alias typeof((function() {
foreach (key, elem; Init!(T)) return key; assert(false);
})()) KeyType;
}
编译时字符串散列。您可以使用它来混淆代码中的嵌入字符串。只需搜索“哈希”。该页面上还有很多其他有趣的示例。
一个统一类型的模板结构(它不会让你犯单元错误。)
一个例子是D 标准库中的位域工具,它为从用户指定的布局开始的位域操作生成代码。
Tuple 设施是另一个例子。它根据用户提供的类型和可选名称生成一个元组。除了注入命名字段之外,没有很多生成性的umph,但我认为这是一个说明性的例子。
在不知道 Lambert 的漏洞利用的情况下,我只是将 memoize 添加到标准库中 - 请参阅此处的文档,此处的代码,以及相关的新闻组讨论。
我研究的另一个工具是一个高阶函数,它将积分或实值函数制成表格(例如提供快速指数)。那还没有准备好发布。
一旦在编译期间允许创建对象,将很容易创建例如在编译期间执行所有自动机生成的正则表达式引擎。
我会回答我自己的问题,因为当我问这个问题时,这个问题并不存在。我为垃圾收集器写了一个补丁,它使用模板和编译时自省来为任意复杂的用户定义类型生成指针偏移信息,以允许精确的堆扫描,而不是在编译器中完成。
我写了一个 memoize() 函数,它的头是这样的(代码有点长,粘贴在这里):
自动记忆(TFunc)(TFunc func);
它的作用是,你给它一个函数的地址,它返回一个强类型的委托(与原始函数相同的签名和返回类型)缓存原始函数的返回值,以便使用相同的参数调用它两次只调用底层函数一次。例如,这是一个以线性而非指数时间执行的斐波那契数列的记忆化“递归”定义:
uint fib(uint n) { 返回 n > 0 ?n > 1 ? 记忆(&fib)(n - 1)+记忆(&fib)(n - 2):1:0;}
可以正常调用,如:fib(1000);
编辑:我发布的前一个代码的链接相当可怕;这个版本要优雅得多。
用于从Stream对象读取和写入简单结构的Mixins:
template TStructReader() {
private alias typeof(*this) T;
static T opCall(Stream stream) {
assert(stream.readable);
T ret; stream.readExact(&ret, T.sizeof);
return ret;
}
}
template TStructWriter() {
private alias typeof(*this) T;
void write(Stream stream) {
assert(stream.writeable);
stream.writeExact(this, T.sizeof);
}
}
像这样使用它:
align (1) struct MyStruct {
... definitions here ...
mixin TStructReader;
mixin TStructWriter;
}
auto ms = MyStruct(stream);
ms.write(stream);
LuaD还广泛使用元编程与 Lua 无缝交互。您可以使用单个命令注册整个类。