gpt4 book ai didi

templates - D 如何允许委托(delegate)作为模板参数?

转载 作者:行者123 更新时间:2023-12-04 23:50:55 25 4
gpt4 key购买 nike

在 Andrei Alexandrescu 的“The D Programming Language”中,
有一个将委托(delegate)作为模板参数的示例:

T[] find(alias pred, T)(T[] input)
if(is(typeof(pred(input[0])) == bool))
{
for(; input.length > 0; input = input[1 .. $]) {
if (pred(input[0])) break;
}
return input;
}

unittest {
int[] a = [1,2,3,4,-5,3,-4];
int z = -2;
auto b = find!(delegate(x) { return x < z; })(a);
asssert(b == a[4..$]);
}
Alexandrescu 解释说这是可行的,因为委托(delegate)实际上是一个胖指针,由两部分组成:函数指针和指向其堆栈帧的指针(这就是 z 在其主体内可访问的原因)。除了 find 将“pred”作为 TEMPLATE 参数,而不是作为参数。并且模板参数只能是编译时常量。
我确定我们单元测试中匿名委托(delegate)的地址确实是一个编译时常量,但它的栈帧地址肯定不应该是,那么委托(delegate)如何作为模板参数呢?
这里到底发生了什么?

最佳答案

别名参数生成为给定的特定符号定制的新代码,其中包括上下文中的内容。

我们来看看拆解:

0805c850 <_D6test564mainFZv20__T12__dgliteral1TiZ12__dgliteral1MFNbNfiZb>:
805c850: 55 push ebp
805c851: 8b ec mov ebp,esp
805c853: 83 ec 04 sub esp,0x4
805c856: 8b 48 d8 mov ecx,DWORD PTR [eax-0x28]
805c859: 3b 4d 08 cmp ecx,DWORD PTR [ebp+0x8]
805c85c: 0f 9f c0 setg al
805c85f: 0f b6 c0 movzx eax,al
805c862: c9 leave
805c863: c2 04 00 ret 0x4

这是此处创建的文字委托(delegate)(顺便说一句,没有优化)。有趣的线条是中间的 mov 和 cmp。

请注意,上下文指针被传递给 eax 寄存器中的委托(delegate)。让我们看看它在哪里被调用:
0805c868 <_D6test5632__T4findS18main12__dgliteral1TiZ4findMFNaNbNfAiZAi>:
// snip a bunch of irrelevant code
805c870: 89 45 fc mov DWORD PTR [ebp-0x4],eax
// snip
805c892: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
805c895: 89 95 f8 ff ff ff mov DWORD PTR [ebp-0x8],edx
805c89b: e8 b0 ff ff ff call 805c850 <_D6test564mainFZv20__T12__dgliteral1TiZ12__dgliteral1MFNbNfiZb>

注意那里的两件事:首先,名称:注意 dgliteral 在那里 - 这是针对这个特定参数的特殊生成的函数!

其次,请注意,在 eax 中传递给该函数的任何内容都会被存储并最终也传递给另一个函数。

让我们再上一次调用堆栈,现在我们在 _Dmain 中出现 find 调用:
 805c7da:       89 e8                   mov    eax,ebp
805c7dc: e8 87 00 00 00 call 805c868 <_D6test5632__T4findS18main12__dgliteral1TiZ4findMFNaNbNfAiZAi>

它正在传递基指针!顺便说一句,还记得 0x28 吗?我们也可以在 _Dmain 中看到它,有几行:
 805c7d1:       c7 45 d8 fe ff ff ff    mov    DWORD PTR [ebp-0x28],0xfffffffe

那是 int z = -2;行(-2 在 32 位中表示为 fffffffe)。它像常规局部变量一样存储在堆栈中。

最重要的是,特定的别名参数会生成一个全新的函数,该函数知道所有局部变量的位置。当它被调用时,指向它们的基指针被转发给它,这就是它所需要知道的。

注意顺便说一句,您也可以将局部变量作为别名参数传递并获得类似的代码,它创建了一个直接戳偏移量而不是获取指针的函数。

此外,如果您尝试将运行时委托(delegate)传递给 alias 参数,或者如果您尝试将别名 dg 存储在其他地方,则不会编译。这是一个带有特定案例代码的特殊函数,很多通用委托(delegate)的东西并不适合它。

关于templates - D 如何允许委托(delegate)作为模板参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22358067/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com