类型擦除和互操作性:C++ 中的虚拟二元运算符问题

发布于 2024-10-16 05:34:40 字数 1650 浏览 2 评论 0原文

我在通过覆盖相等运算符比较同一接口的模板实现时遇到问题。

Interface* ptr1 = ...; Interface* ptr2 = ...;
*ptr1 == *ptr2;

我想到的唯一解决方案是强制只比较相同实现的对象,并实现如下比较:

class Interface {
public:
    virtual ~Interface() {}
    virtual bool operator==(const Interface&) const = 0;
};

template <typename T> class Impl : public Interface {
public:
    bool operator==(const Interface& rhs) const {
        assert(typeid(rhs) == typeid(const Impl&));
        const Impl& rhsRef = static_cast<const Impl&>(rhs);
        // ...
    }
};

这个解决方案的问题是它对于我的目的来说太有限了 - 我希望能够比较不同的实现。如果实现数量有限,则可以使用双调度模式。但在我的例子中,Impl 是一个模板,所以双重调度是不可能的,因为它需要一个虚函数模板:

// This obviously doesn't work.

class Interface {
public:
    virtual ~Interface() {}
    virtual bool operator==(const Interface&) const = 0;
    template <typename T2> virtual bool operator==(const Impl<T2>&) const = 0;
};

template <typename T> class Impl : public Interface {
public:
    bool operator==(const Interface& rhs) const {
        return rhs == *this;
    }
    template <typename T2> bool operator==(const Impl<T2>& rhs) const {
        // ...
    }
};

有什么解决方案吗?我需要这个来编写 AnyIterator 类,它可以包装任何 STL 迭代器。但我无法比较 AnyIterators,如果它们包装在不同的类型上,例如 iterator 和 const_iterator:

std::list<int>::iterator it1 = ...; std::list<int>::const_iterator it2 = ...;
AnyIterator<const int> myIter1 = it1; AnyIterator<const int> myIter2 = it2;
it1 == it2;         // This works perfectly.
myIter1 == myIter2; // This doesn't work!

I have problems comparing template implementations of the same interface through overriden equality operator.

Interface* ptr1 = ...; Interface* ptr2 = ...;
*ptr1 == *ptr2;

The only solution I've came up to is to enforce that only identically implemented objects are to be compared and to implement comparison like this:

class Interface {
public:
    virtual ~Interface() {}
    virtual bool operator==(const Interface&) const = 0;
};

template <typename T> class Impl : public Interface {
public:
    bool operator==(const Interface& rhs) const {
        assert(typeid(rhs) == typeid(const Impl&));
        const Impl& rhsRef = static_cast<const Impl&>(rhs);
        // ...
    }
};

The problem in this solution is that it's too limited for my purposes - I'd want to be able to compare different implementations. If there were a limited number of implementations, it would be possible to use double dispatch pattern. But in my case Impl is a template, so double dispatch is not possible, because it would need a virtual function template:

// This obviously doesn't work.

class Interface {
public:
    virtual ~Interface() {}
    virtual bool operator==(const Interface&) const = 0;
    template <typename T2> virtual bool operator==(const Impl<T2>&) const = 0;
};

template <typename T> class Impl : public Interface {
public:
    bool operator==(const Interface& rhs) const {
        return rhs == *this;
    }
    template <typename T2> bool operator==(const Impl<T2>& rhs) const {
        // ...
    }
};

Is there any solution? I need this to write AnyIterator class, which can wrap any STL iterator. But I can't compare AnyIterators, if they are wrapped around different types, for example iterator and const_iterator:

std::list<int>::iterator it1 = ...; std::list<int>::const_iterator it2 = ...;
AnyIterator<const int> myIter1 = it1; AnyIterator<const int> myIter2 = it2;
it1 == it2;         // This works perfectly.
myIter1 == myIter2; // This doesn't work!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不醒的梦 2024-10-23 05:34:40

我认为这里的问题是,在您的界面中使用 operator== 根本没有任何意义。如果您想为您的实现提供比较,那就是另一回事了,例如:

bool operator==(const Impl<T>& other) const {
    // ...
}

即使对于这种情况,我通常也不鼓励创建运算符重载;相反,提供访问器来获取某人可能想要比较的相关属性,并将其留给使用您的代码的人来创建他们想要进行的比较。

对于这些任意比较,您有具体的用例吗?

I think the problem here is that having operator== in your Interface, just doesn't make any sense at all. If you want to provide comparison for your implementation, that's another matter, like:

bool operator==(const Impl<T>& other) const {
    // ...
}

Even for that case, though, I would generally discourage creating operator overloads; instead, provide accessors to get the relevant attributes that someone might want to compare, and leave it up to whoever is using your code to create the comparisons that they want to make.

Do you have a specific use case for these arbitrary comparisons?

春花秋月 2024-10-23 05:34:40

您可以使用 dynamic_cast 而不是 static_cast 并检查 std::bad_cast (在这种情况下始终返回 false)。您可以使用指针dynamic_cast而不是引用强制转换,在这种情况下您只需检查NULL而不是捕获异常。

You can use dynamic_cast instead of static_cast and check for std::bad_cast (and just always return false in that case). You could use a pointer dynamic_cast instead of a reference cast, in which case you'd just have to check for NULL instead of catching an exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文