I'm trying to implement equality for all types that share same base.
Consider std::vector<unique_ptr<Shape>> and that we want to check if a certain given Shape& is equal to a certain shape managed in the vector. The idea is to have a generic solution through a base class, without relying on the exact content of the derived classes and without narrowing it to shapes (which is merely just a usage example).
I came to the following solution, with CRTP and would appreciate comments.
AbstractBase
class AbstractBase {
virtual bool base_equals(const AbstractBase& other) const = 0;
virtual std::ostream& print(std::ostream& out = std::cout) const = 0;
public:
bool operator==(const AbstractBase& other)const {
if(typeid(*this)==typeid(other)) {
return this->base_equals(other);
}
return false;
}
friend std::ostream& operator<<(std::ostream& out, const AbstractBase& ab) {
out << "[" << (void*)&ab << "] ";
return ab.print(out);
}
};
CRTP Base
template<class ActualType>
class Base: public AbstractBase {
virtual bool base_equals(const AbstractBase& other)const override final {
return static_cast<const ActualType&>(*this)
== static_cast<const ActualType&>(other);
}
};
Actual Classes
class A: public Base<A> {
int num;
virtual std::ostream& print(std::ostream& out = std::cout) const {
return out << num;
}
public:
A(int i = 42): num(i) {}
bool operator==(const A& a)const {
return num == a.num;
}
};
class B: public Base<B> {
std::string str;
virtual std::ostream& print(std::ostream& out = std::cout) const {
return out << str;
}
public:
B(const std::string& s = "hello"): str(s) {}
bool operator==(const B& b)const {
return str == b.str;
}
};
Simple Usage Example (Test)
int main() {
A a1, a2, a3 = 5;
B b1, b2, b3 = {"bye"};
std::vector<const AbstractBase*> arr = {&a1, &a2, &a3, &b1, &b2, &b3};
for(auto v1: arr) {
for(auto v2: arr) {
std::cout << *v1 << " == " << *v2 << " ? "
<< std::boolalpha << (*v1 == *v2) << std::endl;
}
}
}
Output
[0x7ffefdb7f0b0] 42 == [0x7ffefdb7f0b0] 42 ? true
[0x7ffefdb7f0b0] 42 == [0x7ffefdb7f0c0] 42 ? true
[0x7ffefdb7f0b0] 42 == [0x7ffefdb7f0d0] 5 ? false
[0x7ffefdb7f0b0] 42 == [0x7ffefdb7f0e0] hello ? false
[0x7ffefdb7f0b0] 42 == [0x7ffefdb7f110] hello ? false
[0x7ffefdb7f0b0] 42 == [0x7ffefdb7f140] bye ? false
[0x7ffefdb7f0c0] 42 == [0x7ffefdb7f0b0] 42 ? true
[0x7ffefdb7f0c0] 42 == [0x7ffefdb7f0c0] 42 ? true
[0x7ffefdb7f0c0] 42 == [0x7ffefdb7f0d0] 5 ? false
[0x7ffefdb7f0c0] 42 == [0x7ffefdb7f0e0] hello ? false
[0x7ffefdb7f0c0] 42 == [0x7ffefdb7f110] hello ? false
[0x7ffefdb7f0c0] 42 == [0x7ffefdb7f140] bye ? false
[0x7ffefdb7f0d0] 5 == [0x7ffefdb7f0b0] 42 ? false
[0x7ffefdb7f0d0] 5 == [0x7ffefdb7f0c0] 42 ? false
[0x7ffefdb7f0d0] 5 == [0x7ffefdb7f0d0] 5 ? true
[0x7ffefdb7f0d0] 5 == [0x7ffefdb7f0e0] hello ? false
[0x7ffefdb7f0d0] 5 == [0x7ffefdb7f110] hello ? false
[0x7ffefdb7f0d0] 5 == [0x7ffefdb7f140] bye ? false
[0x7ffefdb7f0e0] hello == [0x7ffefdb7f0b0] 42 ? false
[0x7ffefdb7f0e0] hello == [0x7ffefdb7f0c0] 42 ? false
[0x7ffefdb7f0e0] hello == [0x7ffefdb7f0d0] 5 ? false
[0x7ffefdb7f0e0] hello == [0x7ffefdb7f0e0] hello ? true
[0x7ffefdb7f0e0] hello == [0x7ffefdb7f110] hello ? true
[0x7ffefdb7f0e0] hello == [0x7ffefdb7f140] bye ? false
[0x7ffefdb7f110] hello == [0x7ffefdb7f0b0] 42 ? false
[0x7ffefdb7f110] hello == [0x7ffefdb7f0c0] 42 ? false
[0x7ffefdb7f110] hello == [0x7ffefdb7f0d0] 5 ? false
[0x7ffefdb7f110] hello == [0x7ffefdb7f0e0] hello ? true
[0x7ffefdb7f110] hello == [0x7ffefdb7f110] hello ? true
[0x7ffefdb7f110] hello == [0x7ffefdb7f140] bye ? false
[0x7ffefdb7f140] bye == [0x7ffefdb7f0b0] 42 ? false
[0x7ffefdb7f140] bye == [0x7ffefdb7f0c0] 42 ? false
[0x7ffefdb7f140] bye == [0x7ffefdb7f0d0] 5 ? false
[0x7ffefdb7f140] bye == [0x7ffefdb7f0e0] hello ? false
[0x7ffefdb7f140] bye == [0x7ffefdb7f110] hello ? false
[0x7ffefdb7f140] bye == [0x7ffefdb7f140] bye ? true
std::vector<unique_ptr<Shape>>and we want to check if a certain givenShape&is equal to a certain shape managed in the vector. \$\endgroup\$