Invalid operator in std::map

Started by
6 comments, last by godecho 15 years, 10 months ago
Im using hgeVector in a std::map as the key. My Tile class is the value.

/** needed for sorting by vector in map */
const bool operator<( const hgeVector& a, const hgeVector& b )
{
	if ( a.x < b.x && a.y < b.y ) return true;
	if ( a.x > b.x && a.y > b.y ) return false;
	return ( a.x < b.x || a.y < b.y );
}

	typedef std::map<hgeVector, Tile*> TileMap;

The problem arises when doing std::map[ position ] = new Tile( id );, the map asserts and gives the error "invalid operator<". However, the first time I insert something into the map it works, but the second time, I get the assert. The first key I insert is (6,-3), which works, but the second one, (7,-4), asserts. The plan with the operator is simple; if both x and y is less, a is less. Else, if neither is less, a is not less. Then the special case; if x or y has the same value, a is less if either is less. Where is my misstake?
Advertisement
I think this is because your operator< is faulty. For example, (6, -3) < (7, -4) and (7, -4) < (6, -3) both return true, but obviously that doesn't make sense.

You should reconsider what less-than means for vectors. Probably the best option would be a sort of lexicographic compare:

const bool operator<( const hgeVector& a, const hgeVector& b ){    return (a.x < b.x) || ( (a.x == b.x) && (a.y < b.y) );}

I havent got the raw brainpower to be able to trace through the logic - but this is the way I structure comparators which I find is fairly readble. we just test each dimension and whether we need another dimension to help resolve otherwise returning false.

const bool operator<( const hgeVector& a, const hgeVector& b )
{
if ( a.x != b.x) return a.x < b.x; // first dim
if ( a.y != b.y) return a.y < b.y; // second dim
return false; // false in case of equality
}
Quote:Original post by Gage64For example, (6, -3) < (7, -4) and (7, -4) < (6, -3) both return true, but obviously that doesn't make sense.


Very true indeed, I wonder how I couldnt spot that. :p

Anyways, both your snippets work, thanks and ++rating to you both! :)

I'm just making a guess about the data types your vector holds, but remember there's something to keep in mind when performing equality tests on floats. Both of the solutions suggested here perform equality tests. They might be fine for your situation, but it's something that should be considered.
Quote:Original post by godecho
I'm just making a guess about the data types your vector holds, but remember there's something to keep in mind when performing equality tests on floats. Both of the solutions suggested here perform equality tests. They might be fine for your situation, but it's something that should be considered.

Actually, it isn't... or, at least, it doesn't turn out to matter. For all the vagaries of floating point math, trichotomy still holds true for real numbers in IEEE-754, and that's all that's needed here. Of course, the resultant ordering isn't going to be particularly coherent, but that's to be expected from any ℜ2→ℜ mapping.
Quote:Original post by godecho
I'm just making a guess about the data types your vector holds, but remember there's something to keep in mind when performing equality tests on floats. Both of the solutions suggested here perform equality tests. They might be fine for your situation, but it's something that should be considered.


Also mixing and matching == and < should probably not be considered good style given the distinction made in stl between the seperate concepts of equality and equivalence - sorry i cant find a good link but scott meyers covers it in effective stl. However for a practical use case that is not generic and confined to floats types i dont think its an issue.
Quote:Original post by Sneftel
Actually, it isn't... or, at least, it doesn't turn out to matter. For all the vagaries of floating point math, trichotomy still holds true for real numbers in IEEE-754, and that's all that's needed here. Of course, the resultant ordering isn't going to be particularly coherent, but that's to be expected from any ℜ2→ℜ mapping.


Ah, good to know.

This topic is closed to new replies.

Advertisement