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.059Linux上にあります。


編集:これは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 ステートメントで type tuple をそのまま使用すると、興味深いことがわかります。タプルには特殊な foreach があります: http://dlang.org/statement.html -> Foreach over Tuples。そして、式型のタプルの場合 (変な言い回しで申し訳ありませんが、残念ながら、それが D での命名方法です)、実際には変数を作成しません - e のすべての使用箇所を型タプルから取得した式に置き換えるだけです。

そして、ここに行きます-ラムダのeはタプルからの式に置き換えられているだけなので、このラムダは委任されていません。私はそれがtypeofであることを確認しました。それは「bool function(S x) pure notrow」です。初めて使用するときに作成され、ラムダコードの e 式を記憶し、そのまま使用するだけだと思います。

バグか、誤機能か、意図したとおりに動作するかについて、誰か他の人にコメントしてもらいたいです。

于 2012-06-19T12:36:02.080 に答える