3

我的 D 程序中有一些相当奇怪的行为,我已将其范围缩小到:

import std.algorithm;
import std.stdio;
import std.traits;

enum E { a, b, c };

struct S { E e; };

void main()
{
    immutable(S)[] source = [ S(E.a), S(E.a), S(E.b) ];
    foreach (e; EnumMembers!E)
    {
        size_t c = count!(x => x.e == e)(source);
        writeln(e, " -> ", c);
    }
}

我希望该程序的输出类似于以下内容:

a -> 2
b -> 1
c -> 0

但实际结果是:

a -> 2
b -> 2
c -> 2

奇怪的是,更改 for 循环以foreach (e; [ E.a, E.b, E.c ])产生我预期的输出。使用foreach (e; [ EnumMembers!E ])也产生了我的预期结果,所以很明显我对范围的使用EnumMemebers是这里的问题......我只是不知道为什么。

我显然做错了什么,但我不知道是什么,并希望得到一些见解。

我的编译器DMD64 D Compiler v2.059在 Linux 上。


编辑:这与 GDC 4.6.3 具有完全相同的行为,因此它不能是编译器错误。


编辑:通过将count调用移至单独的函数:

size_t counte(Range)(E e, Range src)
{
    return count!(x => x.e == e)(src);
}

并将c的初始化更改为size_t c = counte(e, source);,程序按我的预期工作。

4

1 回答 1

3

简短且不完整的答案可能有助于指导挖掘:

EnumMembers!T 是类型元组(http://dlang.org/tuple.html -> Type Tuple ),而不是表达式元组或数组。当您使用 [ EnumMembers!T ] 语法时,元组在编译时用作初始化列表,并创建常规数组,提供预期的行为。

现在,如果您在 foreach 语句中按原样使用类型元组,事情就会变得有趣。元组有一个特殊情况 foreach:http: //dlang.org/statement.html -> Foreach over Tuples。如果是表达式类型的元组(对于奇怪的措辞抱歉,但不幸的是,这就是它在 D 中的命名方式)它并没有真正创建变量 - 它只是用从类型元组中获取的表达式替换 e 的所有用法。

在这里我们开始 - lambda 中的 e 只是替换为来自元组的表达式,所以这个 lambda 不是委托的。我检查了它的 typeof,它是“bool function(S x) pure nothrow”。猜猜它是在第一次使用时创建的,记住 lambda 代码中的 e 表达式,然后按原样使用它。

我需要其他人评论它是错误、功能错误还是按预期工作。

于 2012-06-19T12:36:02.080 回答