d - 为什么我为匿名类设置 "need opCmp"?

标签 d anonymous-inner-class

我不太确定如何解释这一点,所以请让我澄清任何没有意义的地方。我有一个接口(interface)和一个模板函数,它返回基于编译时参数返回匿名内部类的函数:

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 启动期间遇到异常:

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

所以,我查看了 druntime 源代码中的 throwing 行,看起来 opCmp for Object 的默认实现只是抛出。我不会在任何地方比较工厂函数或 MyInterface。我正在将工厂存储为字符串索引关联数组的值,但是当我将匿名类直接存储在该数组中时不需要 opCmp,只有当我开始存储函数时才需要。如果我插入一个 opCmp(使用内存地址),一切似乎都正常工作,但 MyInterface 并不是真正可比的,所以我宁愿不这样做,除非我必须这样做。 如果可能,我想知道在匿名类上调用 opCmp 的原因/位置,以及如何防止或解决它。

注意:对象中 opCmp 的默认实现包括模糊引用错误的注释、注释掉的内存地址比较,然后是抛出版本。

谢谢!

编辑:我应该提一下,我尝试了 windbg 和 ddbg 来准确追踪调用 opCmp 的位置,但在这两种情况下都失败了。 Windbg 没有给出任何有用的信息,因为它顽固地拒绝加载任何符号,ddbg 加载了符号,但是异常发生在初始化期间(在静态模块构造函数之后但在 main 之前)并且推测 ddbg 没有访问运行时符号?

最佳答案

更新:我在玩具示例中特别重现 opCmp 错误时遇到问题,但我想我已经弄清楚发生了什么。
似乎在匿名函数内部创建继承接口(interface)的匿名内部类是错误的(去图)。具体来说,匿名类在虚函数方面表现不佳。即使定义了 opCmp,我也遇到了 toString 和默认构造函数的错误,并且有一些成员什么都不做(但在调用时不抛出或出错)。 __traits(allMembers, MyInterface) 返回预期信息,__traits(allMembers, typeof(anonInstance)) 也是如此,但经常调用列出的成员不起作用。奇怪。
但是,如果我将接口(interface)更改为具有抽象方法的类,则 opCmp 错误得到解决,匿名类的行为符合预期等。我对编译器了解不多,但我认为在编译过程中会构建一个符号表,它将虚函数名称映射到存储在 vtbl 中的内存地址。我认为正在发生的事情是,当返回从接口(interface)派生的匿名类时,生成的 map 会有所不同。这是可能的,因为接口(interface)支持多重继承,因此不能规定绝对的 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.toString 而不是 TestInterface.helloWorld

我打算改天再问这个问题,以防我犯了错误。然后我可能会将此报告为 DMD 中的错误。我将通过只对匿名工厂函数基类型使用抽象类来解决这个问题。 TL;DR 似乎是一个错误。

关于d - 为什么我为匿名类设置 "need opCmp"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9752414/

相关文章:

json - std.json - 与 TRUE、FALSE 和 NULL 值有点混淆

functional-programming - D中函数的类型

d - 使用 File().byLine() 和 fold()

struct - 使用 CTFE 生成结构体别名集

java - 静态方法中的匿名类,引用什么?

operator-overloading - 在 D 中重载 bool 运算符

java - 匿名函数内的回调,未正确获取语法

java - 如何解决内部类的循环依赖?

java - 匿名内部类必须扩展一些父类(super class)?

java - Java中 "asynchronous method"是什么意思?