比较 c++20 中的多态类型

Mat*_*szL 18 c++ polymorphism comparison comparison-operators c++20

我的代码介于 c++17 和 c++20 之间。具体来说,我们在 GCC-9 和 clang-9 上启用了 c++20,它只是部分实现。

在代码中,我们有非常大的多态类型层次结构,如下所示:

struct Identifier {
    virtual bool operator==(const Identifier&other) const = 0;
};

struct UserIdentifier : public Identifier {
    int userId =0;
    bool operator==(const Identifier&other) const override {
        const UserIdentifier *otherUser = dynamic_cast<const UserIdentifier*>(&other);
        return otherUser && otherUser->userId == userId;
    }
};

struct MachineIdentifier : public Identifier {
    int machineId =0;
    bool operator==(const Identifier&other) const override {
        const MachineIdentifier *otherMachine = dynamic_cast<const MachineIdentifier*>(&other);
        return otherMachine && otherMachine->machineId == machineId;
    }
};

int main() {
    UserIdentifier user;
    MachineIdentifier machine;
    return user==machine? 1: 0;
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/er4fsK

我们现在正在迁移到 GCC-10 和 clang-10,但由于某些原因,我们仍然需要在版本 9 上工作(好吧,至少是 clang-9,因为这是 android NDK 目前拥有的)。

上面的代码停止编译,因为实现了关于比较运算符的新规则。可逆运算符== 导致歧义。我不能使用宇宙飞船运算符,因为它没有在版本 9 中实现。但我在示例中省略了这一点 - 我假设任何与 == 一起使用的东西都可以与其他运算符一起使用。

那么:在 c++20 中使用多态类型实现比较运算符的推荐方法是什么?

dfr*_*fri 19

作为中间解决方案,您可以将多态相等性重构operator==operator==基类中定义的非虚拟,该基类以多态方式分派到非运算符虚拟成员函数:

struct Identifier {    
    bool operator==(const Identifier& other) const {
        return isEqual(other);
    }
private:
    virtual bool isEqual(const Identifier& other) const = 0;
};

// Note: do not derive this class further (less dyncasts may logically fail).
struct UserIdentifier final : public Identifier {
    int userId = 0;
private:
    virtual bool isEqual(const Identifier& other) const override {
        const UserIdentifier *otherUser = dynamic_cast<const UserIdentifier*>(&other);
        return otherUser && otherUser->userId == userId;
    }
};

// Note: do not derive this class further (less dyncasts may logically fail).
struct MachineIdentifier final : public Identifier {
    int machineId = 0;
private:
    virtual bool isEqual(const Identifier& other) const override {
        const MachineIdentifier *otherMachine = dynamic_cast<const MachineIdentifier*>(&other);
        return otherMachine && otherMachine->machineId == machineId;
    }
};
Run Code Online (Sandbox Code Playgroud)

现在将不再有歧义,因为isEqual虚拟成员函数的调度将始终在 的左侧参数上完成operator==

const bool result = (user == machine);  // user.isEqual(machine);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此方法可以扩展为使用 [double dispatch](/sf/ask/880742831/),这可以消除对“dynamic_cast”的需要。 (2认同)