c++inheritancecode-reusecomparison-operators

C++ Reuse out-of-class comparsion operators of base for derived class


Snippet

struct A {
    int a;
};

bool operator==(const A& lhs, const A& rhs) { return lhs.a == rhs.a; }

template <typename T>
bool operator==(const A& lhs, const T& rhs) {
    return lhs.a == rhs;
}

template <typename T>
bool operator==(const T& rhs, const A& lhs) {
    return lhs.a == rhs;
}

struct B : public A {
};

int main() {
    A a1, a2;
    B b1, b2;

    auto c1 = a1 == a2;
    auto c2 = static_cast<A>(b1) == static_cast<A>(b2);
    auto c3 = b1 == b2;
}

Is it possible to make the last comparison b1 == b2 work without a static_cast? Is a reuse of the out-of-class comparison operators of A possible without redefining explicit comparison operators for B?

Example on godbolt

EDIT: I forgot to mention that A is immutable to me. I have no access to it and its comparison operators.


Solution

  • Is it possible to make the last comparison b1 == b2 work without a static_cast?

    Yes, you can use SFINAE as shown below:

    bool operator==(const A& lhs, const A& rhs) { return lhs.a == rhs.a; }
    
    template <typename T>
    typename std::enable_if_t<!std::is_same_v<T, B>, bool > operator==(const A& lhs, const T& rhs) {
        return lhs.a == rhs;
    }
    
    template <typename T>
    typename std::enable_if_t<!std::is_same_v<T, B>,bool> operator==(const T& rhs, const A& lhs) {
        return lhs.a == rhs;
    }
    int main() {
        A a1, a2;
        B b1, b2;
    
        auto c1 = a1 == a2;
        auto c2 = b1 == b2; //works now 
        auto c3 = b1 == b2;
    }
    

    Working demo.


    Or with C++20 use requires

    bool operator==(const A& lhs, const A& rhs) { return lhs.a == rhs.a; }
    
    template <typename T> bool operator==(const A& lhs, const T& rhs) 
    requires (!std::is_same_v<T, B>)
    {
        return lhs.a == rhs;
    }
    
    template <typename T>bool  operator==(const T& rhs, const A& lhs) 
    requires (!std::is_same_v<T, B>)
    {
        return lhs.a == rhs;
    }
    

    Demo