使用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

我试图在编译时折叠数组,并将结果存储在枚举中。当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)
    //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,允许使用多个没有类型的标识符。该规范与编译器分开维护,因此遗憾的是存在一些不一致之处。