Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with user provided operator == (with proposed fix) #2121

Closed
AlCash07 opened this issue Dec 18, 2020 · 0 comments · Fixed by #2128 or sakibguy/Catch2#6
Closed

Problem with user provided operator == (with proposed fix) #2121

AlCash07 opened this issue Dec 18, 2020 · 0 comments · Fixed by #2128 or sakibguy/Catch2#6
Labels

Comments

@AlCash07
Copy link
Contributor

Describe the bug
The test doesn't compile when the user provides a more general operator == overload than ExprLhs.
operator == in the code sample below is a better match when r-value reference is passed because it accepts forwarding reference (U&&) and ExprLhs accepts only const reference (RhsT const& rhs) https://github.com/catchorg/Catch2/blob/devel/src/catch2/internal/catch_decomposer.hpp#L187

        template<typename RhsT>
        auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
            return { compareEqual( m_lhs, rhs ), m_lhs, "=="_sr, rhs };
        }

Expected behavior
The test should compile.

Reproduction steps

namespace adl {

struct activate_adl {};

struct equality_expression {
    operator bool() const { return true; }
};

template <class T, class U>
constexpr auto operator == (T&&, U&&) {
    return equality_expression{};
}

}

TEST_CASE("User provided equality operator", "[compilation]") {
    REQUIRE(0 == adl::activate_adl{});
}

error: no matching member function for call to 'handleExpr' REQUIRE(0 == adl::activate_adl{});

Fix
My first attempt was to change the operator == definition (and similarly all other operators) to

        template<typename RhsT>
        auto operator == ( RhsT && rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
            return { compareEqual( m_lhs, rhs ), m_lhs, "=="_sr, rhs };
        }

However, this broke a test for bitfields
error: non-const reference cannot bind to bit-field 'v' REQUIRE(0 == y.v);

This can be resolved by two not so clean overloads, maybe you know a better way:

        template<typename RhsT>
        auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
            return { compareEqual( m_lhs, rhs ), m_lhs, "=="_sr, rhs };
        }
        template<typename RhsT, std::enable_if_t<!std::is_arithmetic<std::decay_t<RhsT>>::value, int> = 0>
        auto operator == ( RhsT && rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
            return { compareEqual( m_lhs, rhs ), m_lhs, "=="_sr, rhs };
        }

Unrelated note
I don't think const reference here prolongs the lifetime of rhs, because it's not local but stored in a class: BinaryExpr<LhsT, RhsT const&>. Not sure if it's a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants