7

I have simply declared a structure like this -

struct data{
    int x,y;
};

Now I have declared 2 variables a & b of data type. I've assigned appropriate values to them. Now, I want to check if they are equal! I am trying to do like this -

data a,b;
a.x=12, a.y=24;
b.x=15, b.y=30;
if(a!=b)cout<<"a~b"<<endl;

But the compiler is giving me the following error on the 4th line ->

error: no match for 'operator!=' (operand types are 'data' and 'data')

Where is the problem actually? Isn't this compare supported in C++?? Or I'm making any mistakes??

What is the exact and easiest way to do this?? Do I need to compare each of the elements in the structure separately?? Or there's any other smarter way??

jbsu32
  • 1,036
  • 1
  • 11
  • 31

4 Answers4

29

C++ gives you attribute-by-attribute assignment implicitly, but no comparison for equality or ordering. The reason is "just because", don't look too hard into philosophy.

You must to provide those operators, if needed, by implementing them yourself explicitly, for example:

bool operator<(const Data& other) const {
    if (x < other.x) return true;
    if (x > other.x) return false;
    return y < other.y;
}

bool operator==(const Data& other) const {
    return x == other.x && y == other.y;
}

and so on.

Note also that defining for example == doesn't give you != automatically and defining < doesn't provide >= implicitly.

UPDATE

C++20 introduces (will introduce) a new operator <=> (friendly name "spaceship operator") exactly to remove the verbosity of having to define all possible relational operators. In this case adding:

std::strong_ordering operator<=>(const Data& other) const {
    if (auto cmp = x <=> other.x; cmp != 0) return cmp;
    return y <=> other.y;
}

will allow compilation of all relational tests (<, <=, >, >=, ==, !=) between elements of the class based on checking x first and, if that check doesn't resolve, checking y instead.

6502
  • 112,025
  • 15
  • 165
  • 265
  • 3
    `return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y);` is so convenient, less error prone that the manual way. – Jarod42 Aug 10 '16 at 13:03
6

You have to implement all operators explicitely that you intent to use. In your case, you will need to supply bool operator!=(const data&, const data&).

A nice way to implement it for PODs like this is to use std::tuple since it already implements ordering:

#include <tuple>

// ...

bool operator!=(const data& p_lhs, const data& p_rhs)
{
    return std::tie(p_lhs.x, p_lhs.y) != std::tie(p_rhs.x, p_rhs.y);
}

std::tie (documentation) creates a temporary tuple of references. Those two tuples can then be compared, since std::tuple defines all comparison operators, as shown here.

I chose to implement operator!= as a free function. You can, of course, choose to implement it as member of your class:

struct data
{
    bool operator!=(const data& p_rhs) const
    {
        return std::tie(x, y) != std::tie(p_rhs.x, p_rhs.y);
    }

    int x, y;
};

Of course you should define all other operators, too. Remember that you can implement most operators by delegating to others.

nshct
  • 1,197
  • 9
  • 29
  • I didn't know about tie! Your answer helped me to learn that. But sadly my codeblocks ide didn't support it :( although I successfully run it in www.ideone.com :) – jbsu32 Aug 10 '16 at 13:27
3

Automatic C++ comparisons are coming in C++20, so you can just add a special operator to indicate that you need default comparisons when new standard is out.

class Point {
 int x;
 int y;
public:
 auto operator<=>(const Point&) const = default;
 // ... non-comparison functions ...
};

https://en.cppreference.com/w/cpp/language/default_comparisons

Vasaka
  • 1,953
  • 1
  • 19
  • 30
0

You have to implement bool operator != (const data&, const data&);.

Possible implementation (in c++11):

#include <tuple>

//...

bool operator == (const data& lhs, const data& rhs) {
    return std::tie(lhs.x, lhs.y) == std::tie(rhs.x, rhs.y);
}

bool operator != (const data& lhs, const data& rhs) {
    return !(lhs == rhs);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302