Type erasure and interoperability: virtual binary operator issues in C++
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 ~In开发者_如何学Goterface() {}
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!
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?
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.
精彩评论