D 函数返回自动引用
D functions returning auto ref
函数上的 return 类型自动引用是什么意思?我只是不理解它。我从 Ali Çehreli 的在线书籍中拿了一个例子,并尝试以各种方式对其进行改编,并查看了 GDC 生成的汇编器,但我仍然没有真正变得聪明。 (我是一位非常有经验的 asm 和 C 程序员,但刚接触 D。)您什么时候真正需要使用此功能?
auto
return 函数的主要用例是在模板中,其中函数体根据某些编译时参数发生变化。 auto ref
只是将其扩展为也允许 ref
return。看:
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
。那里没有花哨的 ref return。这是 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 也可以!)字节顺便说一句,75736520726566 部分 - 将 0x75 识别为 'u' 和 0x66 为 'f'。D 损坏的名称可能会长得离谱,但一旦你了解它,该模式就非常容易阅读。)
该代码调用 new
,因此主体更复杂,但请注意 eax 仍然保存着 return 值……指针。现在,让我们从 auto ref
中取出 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]
了吗?它不再 returning 指针(当然,这就是 ref
return 在幕后所做的),但现在它指向的是 - 一个正常的,非引用, 值 return.
这就是auto
return和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
。
实际用例是,模板可能会根据各种参数做出更复杂的决定,决定在它们的主体中做什么,从而决定它们的 return 类型。它可能只是 return 传递给它的参数的任何类型,它可能会检查平台版本(那将是一些丑陋的代码大声笑),无论如何。 auto ref
允许您涵盖各种类似的情况,而无需自己编写单独的函数签名(以及函数体)。
auto
用于当您希望编译器确定函数将 return 的类型时。例如,下面两个函数是相同的:
uint returnAUint(){
uint r=256;
return r;
}
auto function2(){
uint r=256;
return r;
}
和ref
意味着函数将return一个pointer/reference。所以 auto ref
是一个函数,它将 return 一个指向编译器必须自行识别的数据类型的指针。
函数上的 return 类型自动引用是什么意思?我只是不理解它。我从 Ali Çehreli 的在线书籍中拿了一个例子,并尝试以各种方式对其进行改编,并查看了 GDC 生成的汇编器,但我仍然没有真正变得聪明。 (我是一位非常有经验的 asm 和 C 程序员,但刚接触 D。)您什么时候真正需要使用此功能?
auto
return 函数的主要用例是在模板中,其中函数体根据某些编译时参数发生变化。 auto ref
只是将其扩展为也允许 ref
return。看:
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
。那里没有花哨的 ref return。这是 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 也可以!)字节顺便说一句,75736520726566 部分 - 将 0x75 识别为 'u' 和 0x66 为 'f'。D 损坏的名称可能会长得离谱,但一旦你了解它,该模式就非常容易阅读。)
该代码调用 new
,因此主体更复杂,但请注意 eax 仍然保存着 return 值……指针。现在,让我们从 auto ref
中取出 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]
了吗?它不再 returning 指针(当然,这就是 ref
return 在幕后所做的),但现在它指向的是 - 一个正常的,非引用, 值 return.
这就是auto
return和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
。
实际用例是,模板可能会根据各种参数做出更复杂的决定,决定在它们的主体中做什么,从而决定它们的 return 类型。它可能只是 return 传递给它的参数的任何类型,它可能会检查平台版本(那将是一些丑陋的代码大声笑),无论如何。 auto ref
允许您涵盖各种类似的情况,而无需自己编写单独的函数签名(以及函数体)。
auto
用于当您希望编译器确定函数将 return 的类型时。例如,下面两个函数是相同的:
uint returnAUint(){
uint r=256;
return r;
}
auto function2(){
uint r=256;
return r;
}
和ref
意味着函数将return一个pointer/reference。所以 auto ref
是一个函数,它将 return 一个指向编译器必须自行识别的数据类型的指针。