类型擦除和互操作性:C++ 中的虚拟二元运算符问题
我在通过覆盖相等运算符比较同一接口的模板实现时遇到问题。
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为这里的问题是,在您的界面中使用
operator==
根本没有任何意义。如果您想为您的实现提供比较,那就是另一回事了,例如:即使对于这种情况,我通常也不鼓励创建运算符重载;相反,提供访问器来获取某人可能想要比较的相关属性,并将其留给使用您的代码的人来创建他们想要进行的比较。
对于这些任意比较,您有具体的用例吗?
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: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?
您可以使用
dynamic_cast
而不是static_cast
并检查std::bad_cast
(在这种情况下始终返回 false)。您可以使用指针dynamic_cast而不是引用强制转换,在这种情况下您只需检查NULL而不是捕获异常。You can use
dynamic_cast
instead ofstatic_cast
and check forstd::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.