D如何允许代理作为模板参数? [英] How does D allow delegates as template parameters?

查看:138
本文介绍了D如何允许代理作为模板参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Andrei Alexandrescu的D编程语言中,

In "The D Programming Language" by Andrei Alexandrescu,

有一个示例,其中委托作为模板参数:

there's an example where a delegate is taken as a template parameter:

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解释说,这是因为一个代表实际上是一个胖指针,由两个部分:函数指针和指向其堆栈框架的指针(这就是为什么z可以在其内部访问)。除了find将pred作为TEMPLATE参数,而不是参数。而且模板参数只能是编译时常量。

Alexandrescu explains that this works because a delegate is actually a fat pointer consisting of two parts: the function pointer and the pointer to its stack frame (which is why z is accessible inside its body). Except that find takes "pred" as a TEMPLATE parameter, not as an argument. And template arguments can only be compile-time constants.

我确定在单元测试中匿名委托的地址确实是一个编译时常数,但是它的堆栈框架的地址肯定不应该,那么代理如何作为模板参数?

I'm sure the address of the anonymous delegate in our unit test is indeed a compile-time constant, but the address of its stack-frame certainly shouldn't be, so how can the delegate be taken as a template parameter?

这里真的发生了什么?

推荐答案

别名参数会为给定的特定符号生成自定义的新代码,其中包括内容中的内容。

An alias parameter generates new code custom made for the particular symbol given, which includes stuff in-context.

我们来看看反汇编:

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

这是这里创建的文字代理(不优化btw)。有趣的是中间的mov和cmp。

This is the literal delegate created here (without optimizations btw). The interesting lines are the mov and cmp in the middle.

请注意,上下文指针被传递给eax寄存器中的一个委托。我们来看看这个名字:

Note that the context pointer is passed to a delegate in the eax register. Let's see where this is called:

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在那里 - 这是一个特殊的这个特定参数的生成函数!

Notice two things there: first, the name: notice that dgliteral is in there - this is a special-generated function for this specific argument!

其次,请注意,在eax中传递给这个函数的东西都被存储并最终传递给其他函数。

Second, notice that whatever was passed to this function in eax gets stored and ultimately passed to the other function too.

我们再一次上电一下,现在我们在_Dmain找到呼叫出现:

Let's go up the call stack one more time, now we're in _Dmain where the find call appears:

 805c7da:       89 e8                   mov    eax,ebp
 805c7dc:       e8 87 00 00 00          call   805c868 <_D6test5632__T4findS18main12__dgliteral1TiZ4findMFNaNbNfAiZAi>

它传递基本指针! BTW,记得0x28?我们可以在_Dmain中看到它,几行排列:

It is passing the base pointer! BTW, remember that 0x28? We can see it in _Dmain too, a couple lines up:

 805c7d1:       c7 45 d8 fe ff ff ff    mov    DWORD PTR [ebp-0x28],0xfffffffe

这是 int z = -2; / code> line(-2表示为fffffffe,32位)。它像一个常规的局部变量一样存储在堆栈中。

That's the int z = -2; line (-2 is represented as fffffffe in 32 bit). It is stored in the stack like a regular local variable.

底线是什么,特定的别名参数会生成一个全新的功能知道在哪里找到所有的局部变量。当它被调用时,它们的基础指针被转发给它,这是所有它需要知道的。

Bottom line, what happens is that particular alias argument generates a whole new function which knows where all the local variables are found. When it is called, the base pointer to them is forwarded to it, which is all it needs to know.

注意,你也可以传递局部变量作为别名参数并获得类似的代码,它会产生直接偏移偏移量的函数,而不是使用指针。

Note btw that you can also pass local variables as alias params and get similar code, it makes a function which pokes the offset directly rather than taking a pointer.

此外,如果您尝试将运行时代理传递给别名参数,或者如果您尝试将别名dg存储在别的地方,那将不会编译。这是一个具有特定于特定代码的特殊功能,很多通用代理的东西不太适用。

Also, if you try to pass a runtime delegate to the alias argument, or if you try to store the alias dg somewhere else, that will not compile. This is a special function with case-specific code, a lot of generic delegate stuff doesn't quite work for it.

这篇关于D如何允许代理作为模板参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆