3

これをどう説明したらいいのかよくわからないので、意味をなさないものを明確にするようにお願いします。コンパイル時の引数に基づいて匿名の内部クラスを返す関数を返すインターフェイスとテンプレート関数があります。

interface MyInterface {
    void getName();
}
MyInterface function() getMyInterfaceFactory(string name)() {
    return function() {
        return new class MyInterface {
            void getName() { //Do something involving name here }
        };
    };
}

現在は、匿名オブジェクトを直接返すために使用されていましたgetMyInterfaceFactory()getMyInterface()すべてがうまくいきました。ファクトリ関数を追加すると、オブジェクトからの起動中に例外が発生し始めました。

object.Exception.....(102): need opCmp for class mymodule.getMyInterfaceFactory!("someargument").getMyInterfaceFactory.__funcliteral14.__anonclass13

そこで、druntime ソースの throwing 行を調べたところ、Object の opCmp のデフォルト実装が単に throw しているように見えます。私はファクトリ関数やMyInterfaces をどこでも比較していません。ファクトリを文字列インデックス連想配列の値として格納していますが、匿名クラスをその配列に直接格納していたときは opCmp は必要なく、関数の格納を開始したときだけでした(メモリ アドレスを使用して) opCmp を挿入すると、すべてが正常に動作するように見えますが、MyInterface は実際には比較できないため、必要がない限り実行しないことをお勧めします。可能であれば、匿名クラスで opCmp が呼び出される理由/場所、およびそれを回避または回避する方法を知りたいです。

注: Object の opCmp のデフォルトの実装には、漠然とバグを参照するコメント、コメント アウトされたメモリ アドレス比較、およびスロー バージョンが含まれます。

ありがとう!

編集:私は、windbg と ddbg の両方を試して、opCmp が呼び出された場所を正確に追跡しようとしましたが、どちらの場合も失敗しました。Windbg はシンボルの読み込みを頑固に拒否し、ddbg はシンボルを読み込みましたが、初期化中 (静的モジュール コンストラクターの後、メインの前) に例外が発生し、おそらく ddbg は druntime シンボルにアクセスできなかったため、有益な情報を提供しませんでしたか?

4

1 に答える 1

0

更新: 特におもちゃの例で opCmp エラーを再現するのに問題がありますが、何が起こっているのか理解できたと思います。
匿名関数内でインターフェースを継承する匿名内部クラスを作成するのはバグがあるようです (図を参照)。具体的には、匿名クラスと仮想関数に関して適切に動作しません。opCmp が定義されていても、toString とデフォルトのコンストラクターでエラーが発生し、単に何もしない (ただし、呼び出されたときにスローもエラーもしない) メンバーがありました。__traits(allMembers, MyInterface)期待される情報を返しますが、__traits(allMembers, typeof(anonInstance))リストされているメンバーを頻繁に呼び出すことはできません。変。
しかし、インターフェイスを抽象メソッドを持つクラスに変更すると、opCmp エラーが解決され、匿名クラスが期待どおりに動作するなどです。コンパイラについてはよくわかりませんが、コンパイル中にシンボル テーブルが構築されると思います。仮想関数名を vtbl に格納されているメモリ アドレスにマップします。インターフェイスから派生した匿名クラスを返すときに、生成されるマップが異なることが起こっていると思います。これが可能なのは、インターフェースが複数の継承をサポートしているためであり、絶対 vtbl マッピングを規定することはできません。ただし、クラスでは、すべての継承者が同じマッピング スキームに固執する必要がある可能性があります (そうかどうかはわかりませんが、可能な場合もあります)。
繰り返しますが、私は本当に確信が持てませんが、症状に合っているようです.opCmpは、どこでも使用していないにもかかわらず呼び出されます. 特に opCmp が問題だとは思いません。Object で定義されたすべての仮想関数が脆弱であると思います。私はこれを次の方法でサポートできました。

testopcmphelper.d
interface TestInterface {
    string helloWorld();
}
class TestClass {
    abstract string helloWorld();
}

testopcmp.d
import testopcmphelper;
import std.stdio;

void invokeFn(TestInterface function() f) {
    auto t = f();
    auto s = t.helloWorld();
    writeln(s);
}

unittest {
    auto f = function() {
        return new class TestInterface {
            string helloWorld() {
                return "Hello World!";
            }
        };
    };
    invokeFn(f);
}

void invokeFn(TestClass function() f) {
    auto t = f();
    auto s = t.helloWorld();
    writeln(s);
}

unittest {
    auto f = function() {
        return new class TestClass {
            string helloWorld() {
                return "Goodbye World!";
            }
        };
    };
    invokeFn(f);
}

どちらが印刷されますか:

src.utilities.testopcmp.__unittest2.__funcliteral1.__anonclass10
Goodbye World!

の代わりにinvokeFn(TestInterface)が呼び出していることを示します。Object.toStringTestInterface.helloWorld

間違いを犯した場合に備えて、質問は別の日に開いたままにします。おそらく、これを DMD のバグとして報告します。匿名ファクトリ関数の基本型には抽象クラスのみを使用して、この問題を回避します。 TL;DR バグのようです。

于 2012-03-19T18:45:36.307 に答える