Templates D如何允许代理作为模板参数?
在Andrei Alexandrescu的“D编程语言”中 有一个将委托作为模板参数的示例:Templates D如何允许代理作为模板参数?,templates,delegates,d,stack-frame,Templates,Delegates,D,Stack Frame,在Andrei Alexandrescu的“D编程语言”中 有一个将委托作为模板参数的示例: T[]查找(别名pred,T)(T[]输入) if(is(typeof(pred(输入[0])==bool)) { 对于(;input.length>0;input=input[1..$]){ if(pred(输入[0])中断; } 返回输入; } 单元测试{ int[]a=[1,2,3,4,-5,3,-4]; int z=-2; 自动b=find!(委托(x){returnx
T[]查找(别名pred,T)(T[]输入)
if(is(typeof(pred(输入[0])==bool))
{
对于(;input.length>0;input=input[1..$]){
if(pred(输入[0])中断;
}
返回输入;
}
单元测试{
int[]a=[1,2,3,4,-5,3,-4];
int z=-2;
自动b=find!(委托(x){returnx
Alexandrescu解释说,这是因为委托实际上是一个胖指针,由两部分组成:函数指针和指向其堆栈框架的指针(这就是为什么z可以在其主体内访问)。除了find将“pred”作为模板参数,而不是参数。模板参数只能是编译时常量
我确信在我们的单元测试中匿名委托的地址确实是一个编译时常量,但是它的堆栈帧的地址当然不应该是,那么如何将委托作为模板参数呢
这到底是怎么回事?alias参数会生成为给定的特定符号定制的新代码,其中包括上下文中的内容 让我们看一下拆解:
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
这就是intz=-2代码>行(-2在32位中表示为FFFFFFF E)。它像常规局部变量一样存储在堆栈中
底线是,特定的alias参数生成了一个全新的函数,它知道所有局部变量的位置。当它被调用时,指向它们的基指针被转发给它,这就是它所需要知道的
请注意,您也可以将局部变量作为别名参数传递,并获得类似的代码,它生成一个直接戳偏移量的函数,而不是使用指针
此外,如果尝试将运行时委托传递给alias参数,或者尝试将alias dg存储在其他位置,则不会编译。这是一个特殊的函数,带有特定于案例的代码,很多通用委托的东西都不适合它
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>
805c7da: 89 e8 mov eax,ebp
805c7dc: e8 87 00 00 00 call 805c868 <_D6test5632__T4findS18main12__dgliteral1TiZ4findMFNaNbNfAiZAi>
805c7d1: c7 45 d8 fe ff ff ff mov DWORD PTR [ebp-0x28],0xfffffffe