D:使用委托和EnumMembers时出现意外输出

时间:2012-06-19 07:12:14

标签: d

我的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的范围就是问题......我只是不知道为什么。

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

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


编辑:这与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);,该程序可以正常运行。

1 个答案:

答案 0 :(得分: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中只用元组中的表达式替换,所以这个lambda不是委托的。我已检查过它的类型,它是“bool function(S x)pure nothrow”。猜猜它是在第一次使用时创建的,在lambda代码中记住e表达式,然后按原样使用它。

我需要其他人评论这是一个错误,错误或按预期工作。