D函数返回自动引用

时间:2016-08-19 14:30:58

标签: function reference d return-type

函数的返回类型自动引用是什么意思?我只是不理睬它。我从AliÇehreli的在线书籍中选取了一个例子,并尝试以各种方式对其进行了调整,并观察了GDC生成的汇编程序,我仍然没有更明智。 (我是一位非常有经验的asm和C程序员,但是D的新手。)你真的需要使用这个功能吗?

2 个答案:

答案 0 :(得分:6)

auto返回功能'主要用例位于模板中,函数体根据某些编译时参数进行更改。 auto ref只是将其扩展为允许ref返回。看哪:

auto ref foo(string magic)() {
   static if(magic == "use ref") {
     int* x = new int;
     return *x;
   } else {
     return 0;
   }
}

void main() {
        foo!""();
        foo!"use ref"();
}

每个唯一的编译时参数集将生成不同的函数。这些不同的功能有完全不同的代码。

这是一个空字符串的函数:

Disassembly of section .text._D3iii15__T3fooVAyaa0_Z3fooFNaNbNiNfZi:

00000000 <_D3iii15__T3fooVAyaa0_Z3fooFNaNbNiNfZi>:
   0:   31 c0                   xor    eax,eax
   2:   c3                      ret
   3:   90                      nop
   4:   90                      nop
   5:   90                      nop
   6:   90                      nop
   7:   90                      nop

正如您所看到的,这是最微不足道的 - return 0。那里没有花哨的参考。这是use ref

的那个
Disassembly of section .text._D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNcNfZi:

00000000 <_D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNcNfZi>:
   0:   55                      push   ebp
   1:   8b ec                   mov    ebp,esp
   3:   b8 00 00 00 00          mov    eax,0x0
   8:   50                      push   eax
   9:   e8 fc ff ff ff          call   a <_D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNcNfZi+0xa>
   e:   83 c4 04                add    esp,0x4
  11:   5d                      pop    ebp
  12:   c3                      ret
  13:   90                      nop
  14:   90                      nop
  15:   90                      nop
  16:   90                      nop
  17:   90                      nop

(被破坏的名称中的字符串为ascii的十六进制字符串(好吧,它实际上是UTF-8,unicode也可以!)字节btw,即75736520726566部分 - 将0x75识别为&#39; u&# 39;和0x66作为&#39; f&#39;。被破坏的名字可能会变得非常长,但是一旦你了解它,这个模式很容易阅读。)

该代码调用new,因此正文更复杂,但请注意eax仍然在那里保存返回值...指针。现在,让我们从ref中取出auto ref并重新编译同样的内容。

第一个功能当然是一样的。第二个改变了:

Disassembly of section .text._D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNfZi:

00000000 <_D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNfZi>:
   0:   55                      push   ebp
   1:   8b ec                   mov    ebp,esp
   3:   b8 00 00 00 00          mov    eax,0x0
   8:   50                      push   eax
   9:   e8 fc ff ff ff          call   a<_D3iii29__T3fooVAyaa7_75736520726566Z3fooFNaNbNfZi+0xa>
   e:   8b 00                   mov    eax,DWORD PTR [eax]
  10:   83 c4 04                add    esp,0x4
  13:   5d                      pop    ebp
  14:   c3                      ret
  15:   90                      nop
  16:   90                      nop
  17:   90                      nop

看到mov eax,DWORD PTR [eax]?它不再返回指针(当然,它是ref在引擎盖下返回的指针),但现在它指向它 - 正常的,非参考值返回。

这就是auto返回与auto ref之间的区别。

为了完整起见,我们将其更改为ref int,看看会发生什么:

$ dmd iii
iii.d(6): Error: constant 0 is not an lvalue
iii.d(11): Error: template instance iii.foo!"" error instantiating

现在仅return 0是一个错误,因为它不是有效的ref

实际用例是模板可以基于各种参数做出更复杂的决定,决定在他们的身体中做什么,从而做出返回类型。它可能只返回传递给它的参数的任何类型,它可能会检查平台版本(那就是一些丑陋的代码lol),无论如何。 auto ref允许您涵盖各种情况,而无需自己编写单独的函数签名(以及函数体)。

答案 1 :(得分:1)

当您希望编译器确定函数将返回哪种类型时,使用

auto。例如,以下两个函数都是相同的:

uint returnAUint(){
   uint r=256;
   return r;
}
auto function2(){
   uint r=256;
   return r;
}

ref表示该函数将返回指针/引用。所以auto ref是一个函数,它将返回一个指向编译器必须自己弄清楚的数据类型的指针。