使用lambda调用时,编译时折叠会导致错误
我试图在编译时折叠数组,并将结果存储在枚举中。当enum和fold调用处于模块级别时,它可以正常工作,但当它都包含在结构中并且使用lambda调用时,编译失败 下面是一些失败代码的简单示例:使用lambda调用时,编译时折叠会导致错误,d,D,我试图在编译时折叠数组,并将结果存储在枚举中。当enum和fold调用处于模块级别时,它可以正常工作,但当它都包含在结构中并且使用lambda调用时,编译失败 下面是一些失败代码的简单示例: import std.algorithm.iteration; import std.stdio; struct Foo { // Version 1 (works) //enum x = [ 1, 2, 3 ].fold!"a * b"; // Version 2 (works
import std.algorithm.iteration;
import std.stdio;
struct Foo
{
// Version 1 (works)
//enum x = [ 1, 2, 3 ].fold!"a * b";
// Version 2 (works)
//enum x = [ 1, 2, 3 ].fold!mult;
// Version 3 (broken)
enum x = [ 1, 2, 3 ].fold!((a, b) => a * b);
pragma(msg, "x = ", x);
}
// Outside of the struct, it works
enum y = [ 1, 2, 3 ].fold!((a, b) => a * b);
pragma(msg, "y = ", y);
int mult(int a, int b)
{
return a * b;
}
void main(){}
注释掉的版本1和版本2编译得很好。只是版本3有问题
编译时,会引发以下错误:
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3690): Error: `this.__lambda2` has no value
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3690): while evaluating: `static assert(((int)).length == fun.length)`
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3697): Error: `this.__lambda2` has no value
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3718): Error: `this.__lambda2` has no value
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3636): Error: template instance `broken.Foo.reduce!((a, b) => a * b).reduceImpl!(false, int[], int)` error instantiating
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(4086): instantiated from here: `reduce!(int[])`
.\broken.d(13): instantiated from here: `fold!(int[])`
x = .\broken.d(13): Error: CTFE failed because of previous errors in `fold`
.\broken.d(16): while evaluating `pragma(msg, x)`
y = 6
Failed: ["C:\\D\\dmd2\\windows\\bin\\dmd.exe", "-v", "-o-", ".\\broken.d", "-I."]
我试过查看错误中提到的源代码,但它使用的概念超出了我目前对D的了解水平
我最初假设lambdas在编译时可能无法正常工作,但enum y的计算结果是正确的,所以我猜这不是因为
我使用的是DMD v2.086.1,但使用LDC 1.16.0和1.14.0时遇到了相同的问题。这是编译器不太擅长于确定lambda是否需要访问其上下文。如果你写了这样的东西:
struct S {
int n;
int fun() {
import std.algorithm.iteration : fold;
return [1,2,3].fold!((a,b) => a*b*n);
}
}
应该清楚的是,上面的lambda需要访问结构中的n。同样,对于enum x=[1,2,3],编译器也会在谨慎方面出错!a、 b=>a*b;,并假设Foo中有一些状态会影响计算结果。将此文件归档为
您已经找到了一些解决方法,还有另一个值得一提的方法-向lambda添加参数类型:
enum x = [ 1, 2, 3 ].fold!((int a, int b) => a * b);
这样,编译器就可以在较早的时候计算出lambda需要什么信息,并且能够计算出它不需要访问周围的作用域。很有趣,谢谢!关于lambda中的参数类型-我很好奇为什么添加参数类型会有帮助,但是规范只给我留下了更多的问题:根据这一点,没有类型a,b=>的版本。。。似乎根本不合法。你知道使用该语法时会发生什么吗?这是规范中的一个错误。可能有人认为ParameterWithMemberAttributes是规范中的另一个错误,它解析为parameterList,允许使用多个没有类型的标识符。该规范与编译器分开维护,因此遗憾的是存在一些不一致之处。