C++ struct has no default memberwise comparison for operator==?!

Started by
30 comments, last by Xentropy 16 years, 10 months ago
Everything I've read says structs in C++ should have a default operator== defined automatically that uses memberwise comparison. However, VS2005 doesn't seem to think so. Simple sample code to illustrate issue:

struct testStruct {
	int data1;
	int data2;
	int data3;
};

int main(void) {
	testStruct test;
	testStruct test2;

	if (test == test2) {
		// do something
	}
	
	return 0;
}
Result: error C2676: binary '==' : 'testStruct' does not define this operator or a conversion to a type acceptable to the predefined operator If structs truly shouldn't have a default memberwise operator== implicitly supplied by the compiler, is there a way to define one explicitly that doesn't involve an incredibly long and annoying bit of code (along the lines of if ((member1 == rhs.member1) && (member2 == rhs.member2) && (member3 == rhs.member3) ... )) for a structure with several dozen members? Please tell me there's something very simple I'm missing, because if not, I have a few hundred lines of practically-meaningless code to write for several classes.
Advertisement
Well actually I don't work with structs ever so I am not sure if you can do operator overloading there but if it was classes for example you could just overload the == operator for that class.
Structs are just classes with default public access instead of default private.

I know I can overload the operator explicitly (as I mentioned), but I have about a dozen classes, each of which uses a data structure with upwards of 50 members. To define an overload of operator== would involve TONS of code. I was hoping for some method that didn't involve typing an entire novel just to implement comparison. Looks like I'm out of luck though. :(

Thanks.
http://msdn2.microsoft.com/en-us/library/sah8k6f4(vs.80).aspx

That link suggests this idea:

struct E {
// operator int();
};

int main()
{

E e1, e2;
e1 == e2; // uncomment operator int in class E, then
// it is OK even though neither E::operator==(E) nor
// operator==(E, E) defined. Uses the conversion to int
// and then the builtin-operator==(int, int)
}

Not sure if that helps :-\
"I'd rather know one thing, no matter how ordinary, than discourse endlessly on great issues." -- Galileo
Quote:Original post by F1N1TY
http://msdn2.microsoft.com/en-us/library/sah8k6f4(vs.80).aspx

That link suggests this idea:

struct E {
// operator int();
};

int main()
{

E e1, e2;
e1 == e2; // uncomment operator int in class E, then
// it is OK even though neither E::operator==(E) nor
// operator==(E, E) defined. Uses the conversion to int
// and then the builtin-operator==(int, int)
}

Not sure if that helps :-\


Nope as this can only work in situations where there is only one member, in which case writing a real operator= is trivial.

Never use implicit operator functions.You will find that the compiler starts being very free with where it does such conversions, not always where you expect.
Quote:Original post by Xentropy
I have about a dozen classes, each of which uses a data structure with upwards of 50 members.


Jebus, what the hell are you doing to involve such unwieldy structures requiring comparison semantics?
Well, if that doesn't help, this conversation from GDNet IRC will:

<F1N1TY> you guys know anything about this: (Link to this forum)
<Zao> F1N1TY: Afair, there's no default op==
<Zao> Only the ctor, cctor, op= and dtor are automagic.
"I'd rather know one thing, no matter how ordinary, than discourse endlessly on great issues." -- Galileo
Sadly, that isn't too helpful since it doesn't even show how E::int() is defined, just the declaration. And a structure that's several kilobytes long isn't going to fit in any built-in type, so I don't see how casting the structures is going to help me.

Thanks for trying, though. :)

Just for more background if anyone wonders why I have such large structures, I'm reading records from a database file, and some of the records are quite large. To compare one record to another to find out if it's equal requires every member of the structures be compared. It seems to me like such a simple method of comparison would be implicitly assumed. It may not always be correct, but it'd at least mean only overloading operator== in those cases instead of every case. I'm comparing actual data, not pointers or references, so memberwise comparison would work fine. (I'm storing strings in std::strings so == is defined for those too.)
Normally you'd compare row keys, not row data.

Assuming I actually needed a data-comparison function (YAGNI!!!), there's a couple of options.

1) If you want your structures to be "POD", evil #define magic involving BOOST_PP_*.

2) If not-quite-"POD" is okay, having the subcomponents of a row structure automatically register themselves in a table of some sort that allows iteration over the elements both for loading database entries or performing operations on them instead of hardcoding everything about each row every time. Possibly using BOOST_PP_* magic again, but it's avoidable here.

3) Not-at-all-"POD", instead pretending C++ is a dynamic language by making row elements an array of boost::variant< std::string, int, ... > or similar (with view accessors for easy access and improved type checking if desired).
If your structs are POD types (Plain Old Data), then you can safely and portably (is that even a word? [smile]) do a memcpy in your operator==(). If you're feeling really game you may be able to get away with doing this for non-POD types as well, but whether this will work or not depends on the types involved and your compiler.....and it is in no way portable.

struct testStruct {	int data1;	int data2;	int data3;	testStruct& operator=(const testStruct& rhs) {		memcpy(reinterpret_cast<char*>(this), 		       reinterpret_cast<const char*>(&rhs),		       sizeof(testStruct));	}};int main(void) {	testStruct test;	testStruct test2;	if (test == test2) {		// do something	}		return 0;}


EDIT: Umm.....I have no idea why I was thinking operator=() but typing operator==(). Replace memcpy with memcmp and the same hold though [rolleyes]

[Edited by - joanusdmentia on June 8, 2007 7:21:29 AM]
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V

This topic is closed to new replies.

Advertisement