Why can't this std::find compare these objects

Viewed 998

Usually when I do an std::find I'll put a predicate as the third argument, but this time I thought I'd do it differently, I don't understand why it doesn't work.

#include <iostream>
#include <vector>
#include <algorithm>

struct RenderJob
{
    RenderJob() {};
    int renderJob_ID;
    bool operator==(RenderJob& rhs) { return rhs.renderJob_ID == this->renderJob_ID; }
};

int main()
{
    RenderJob foo;
    RenderJob foo2;
    foo == foo2; // Works

    std::vector<RenderJob> renderJobs;

    std::find(renderJobs.begin(), renderJobs.end(), foo); // Doesn't work
}

binary "==" no operator found which takes a left-handed operand of type RenderJob (or there is no acceptable conversion)

Edit:: Well thanks for the answers. Here are some examples of why it fails

    RenderJob foo;
    RenderJob foo2;
    foo == foo2; // Works

    std::vector<RenderJob> renderJobs;

    std::vector<RenderJob>::const_iterator constit = renderJobs.begin();

    *constit == foo2;  // Doesn't work

Even simpler as an illustration:

 const RenderJob* pToRenderJob;

*pToRenderJob == foo2;  // This fails because the pointed to 
                        // object is const, and cannot call the 
                        // operator== function because the actual function
                        // definition is not const. 

If it were the other way around:

foo2 == *pToRenderJob; // This would fail because the 
                        // operator==(RenderJob&) the actual argument 
                        // is not const. Very subtle rules
3 Answers

You left your const qualifiers off.

bool operator==(const RenderJob& rhs) const { ... }

Looks to me like a const-correctness problem. Try something like this instead:

bool operator==(RenderJob const &rhs) const { 
    return rhs.renderJob_ID == this->renderJob_ID; 
}

Doing the comparison yourself worked because you were just passing plain objects that weren't temporaries, nor were they const qualified. With std::find, the comparison function will (at least usually) receive a reference to the object in the collection (which will normally be const qualified), so it needs to be able to receive a const-qualified reference.

But that still doesn't make sense, in the above example, the right hand side is foo2, which is not constant, which should go to the non-const operator==. Unless there's a general rule that const and non const can't be compared.

There is no rule in the language that const and non-const objects cannot be compared. You have to make sure that they can be compared by using proper const qualifiers.

The line

*pToRenderJob == foo2;

is equivalent to

pToRenderJob->operator==(foo2);

That does not work since pToRenderJob cannot be used to call a non-const member function. foo2 is not the problem here.

If you use

foo2 == *pToRenderJob

it is equivalent to

foo2.operator==(*pToRenderJob)

That is also a problem since the argument to the function is a const object while your function expects a non-const reference. Once again, foo2 is not the problem.

Making the function a const member function and making the argument a const reference makes sure that all combinations of const and non-const objects on both sides of the operator can be used without any problem.

Related