Find equal instance in a c++ set - c++

I'm using a c++ STL set and I want to know if it's present in the set an equivalent instance. To retrive the instance I'm using the find set method. The problem is that it doesn't work. I think the problem is in my comparator object:
bool SetComparator::operator ()( const Point* i1, const Point* i2 ) const {
if ( *i1 == *i2 )
return false;
return true;
}
The operator == is redefined for the class Point in a simple way:
bool Point::operator ==( const Point& p ) const {
if (x == p.x && y == p.y)
return true;
return false;
}
After a debugging I can see that the find method calls operator() but it doesn't find the same instance so the find returns end() but I know that there is an equal object. I think the problem is related to the set internal order. How can I do?

std::set uses partial ordering (i.e. the operator<), so when you pass in an operator that can only decide equality, you break the assumption of the implementation of std::set. Your SetComparator has to behave similar to std::less.
For example std::pair (utility) implements relational operators for two items, e.g. for operator<:
template <class T1, class T2>
bool operator< (const std::pair<T1,T2>& lhs, const std::pair<T1,T2>& rhs) {
return lhs.first<rhs.first || (!(rhs.first<lhs.first) && lhs.second<rhs.second);
}
note that (!(rhs.first<lhs.first) && lhs.second<rhs.second) is a workaround for (rhs.first == lhs.first && lhs.second < rhs.second) using only operator<
If you only want to check for equality maybe using std::set is the wrong decision. If you can hash your objects, you could use a std::unordered_set (C++11 and later).

Related

Invalid Operands to binary expression(const point and const point

map<pair<int,int>,int>pairOfNumbers;
pairOfNumbers.insert(pair<pair<int,int>,int>({1,2},2));
this is working, but
map<pair<point,point>,int>PointsOnLine;
PointsOnLine.insert(pair<pair<point,point>,int>(make_pair(points[i],points[j]),count));
this doesn't.
point is just a structure of two ints x and y;
I keep getting the error 'Invalid Operands to binary expression(const point and const point' this is the structure of point.
struct point
{
int x;
int y;
public:
bool operator==(const point& p)
{
if(x==p.x && y==p.y)
return true;
else
return false;
}
bool operator!=(const point& p)
{
if(x==p.x &&y==p.y)
return false;
else
return true;
}
};
how do I insert two points and distance between them in the map?
in Xcode I get this error
Your point type does not support weak-ordering. It has no method of determining is-less-than. You may think you don't need that because your point is actually tucked into a std::pair<point,point> but you do.
std::pair<T1,T2> supports weak ordering only if T1 and T2 do. In your case, they're the same type, so for a std::pair<point,point> to be used as key in a std::map<std::pair<point,pint>,T>, point must support weak ordering.
To support weak ordering, you must either provide an operator< that compares two of your objects in question, or a comparator functor type that does the same thing. The easiest way for you to do this would be:
#include <tuple>
struct point
{
int x;
int y;
bool operator <(const point& p) const
{
return std::tie(x, y) < std::tie(p.x, p.y);
}
bool operator ==(const point& p) const
{
return !(*this < p || p < *this);
}
bool operator !=(const point& p) const
{
return *this < p || p < *this;
}
};
I took liberty to redefine operator == and operator != to utilize the weak order properties of the proper operator <. It wasn't necessary, but ultimately it's just easier if operators root to as basic code as possible. With the above change you should be able to use both point and std::pair<point,point> as key types in std::map and std::set. In truth, a strict weak ordering can define all of the basic comparators (<=, >, >=, !=, ==) as derivations from operator < in one form or another (or relative to something that does). I challenge you to consider them, try implementing them, and above all, writing some test harnesses that verify your implementation.

How do I use GLM Vector Relational Functions?

I'm trying to create an std::set of GLM vectors (glm::vec3 specifically). Since C++ does not know how to perform < operation on the vectors, I must pass in a Compare funciton.
I can write my own by creating a structure like so:
struct compareVec
{
bool operator() (const glm::vec3& lhs, const glm::vec3& rhs) const
{
return lhs.x < rhs.x && lhs.y < rhs.y && lhs.z < rhs.z;
}
};
std::set< glm::vec3, compareVec > myset;
However, I'm sure that GLM includes their own vector comparison functions.
I found the following resource, but I'm unsure of how to use it:
https://glm.g-truc.net/0.9.4/api/a00137.html
How can I pass one of these comparison functions to my set?
Ok, almost there! The glm::lessThan returns a vector type, not a bool. This is why your comparator does not work. You could use glm::all on it to get a bool. From Documentation of glm::all
bool glm::all ( vecType< bool > const & v )
Returns true if all components of x are true.
Template Parameters
vecType Boolean vector types.
If this makes sense for you, you have to decide for yourself, even if I recommend against it as this, as far as I understand, will lead to the following issue:
Consider:
lhs = (1,2,3)
rhs = (0,1,4)
Than:
lhs < rhs ==> false, since lhs.x and lhs.y are larger than the corresponding components of rhs
rhs < lhs ==> false, since rhs.z component is larger than lhs.z
Since neither vector can be ordered to be less, this implies that they are equal. I doubt this is the behavior you have in mind (I was already warning you about this).
If you still decide to use it, here is a minimal working example tested on MSVC2010:
#include <set>
#include <glm/vec3.hpp>
#include <glm/detail/func_vector_relational.hpp>
struct compareVec
{
bool operator() (const glm::vec3& lhs, const glm::vec3& rhs) const
{
return glm::all(glm::lessThan(lhs, rhs));
}
};
int main()
{
std::set<glm::vec3, compareVec> myset;
return 0;
}
Maybe this helps.
By giving priority to early components of the vec, we can avoid (1,2,3) and (0,1,4) from both being less than each other. what we want is something that does the same thing as this:
lh.x != rh.x ?
lh.x < rh.x
: lh.y != rh.y ?
lh.y < rh.y
: lh.z < rh.z
I believe this should work as the compareVec:
struct compareVec {
bool operator() (const glm::vec3& lhs, const glm::vec3& rhs) const
{
glm::vec3 nequ = glm::notEqual(lhs, rhs);
return glm::lessThan(lhs, rhs)[nequ[0] ? 0 : nequ[1] ? : 1 : 2];
}
};
I couldn't find a glm function that returns the first index that is true, so I just used nequ[0] ? 0 : nequ[1]? : 1 : 2

Creating a composite type from two enum classes, ready for STL map

I would like to create a composite type out of two enum classes.
enum class Color {RED, GREEN, BLUE};
enum class Shape {SQUARE, CIRCLE, TRIANGLE};
class Object {
Color color;
Shape shape;
public:
};
In order to use Object in an STL container like std::map<> I would need to overload the less-than operator. However, in order to flatten both enum classes into one linear index I somehow need the number of elements (NoE) of the enum classes:
friend bool operator< (const Object &lhs, const Object &rhs) {
return NoE(Shape)*lhs.color+lhs.shape < NoE(Shape)*rhs.color+rhs.shape;
}
How can this be done without entering the same information (number of elements) in two places in the program in a nice way? (Nice way means no FIRST_ELEMENT, LAST_ELEMENT, preprocessor magic, etc.)
Question (Number of elements in an enum) is similar but does not address enum classes.
I would like to know what is the best way to implement this kind of composite types in C++11. Is the enum class definition strong enough, or is it necessary to say:?
enum class Color {RED=0, GREEN=1, BLUE=2};
enum class Shape {SQUARE=0, CIRCLE=1, TRIANGLE=2};
As commented and as already stated by others, give precedence to either Shape or Color in the operator< and only compare the other if the first is equal.
An alternative implementation for operator< using std::tie:
#include <tuple>
friend bool operator<(const Object& lhs, const Object& rhs)
{
return std::tie(lhs.color, lhs.shape) < std::tie(rhs.color, rhs.shape);
}
Consider using simply std::tuple<Color, Shape> as the "composite enum." This will come with comparison operators already defined for you, using a dictionary ordering. For example, valid code:
bool b = std::make_tuple(Color::RED, Shape::CIRCLE)
< std::make_tuple(Color::GREEN, Shape::SQUARE);
You don't need a linear index, you can simply compare them lexicographically:
friend bool operator< (const Object &lhs, const Object &rhs) {
if (lhs.color < rhs.color) return true;
else if (lhs.color > rhs.color) return false;
else return lhs.shape < rhs.shape;
}
That's a good question, but you don't actually need the number of Color to compare them :
friend bool operator< (const Object &lhs, const Object &rhs) {
if(lhs.color > rhs.color) {
return false;
}
if(lhs.color < rhs.color) {
return true;
}
return lhs.shape < rhs.shape;
}
You only need to compare shape if color is the same for both.
Using a ternary you can make it look nice too:
friend bool operator< (const Object &lhs, const Object &rhs) {
return lhs.color == rhs.color ? (lhs.shape < rhs.shape)
: (lhs.color < rhs.color);
}
What you are trying to express is that to determine the order of your Objects, you first need to compare the color, and then check the shape in case the color was the same. Instead of linearizing that, if would simply use boolean operators.
friend bool operator< (const Object &lhs, const Object &rhs)
{
return ( (lhs.color < rhs.color)
|| ( (lhs.color == rhs.color ) && ( lhs.shape < rhs.color) ) )
}
EDIT: Actually, you can also use an upper bound for the number of objects, the behaviour will be the same:
friend bool operator< (const Object &lhs, const Object &rhs) {
return 10000*lhs.color+lhs.shape < 10000*rhs.color+rhs.shape;
}
but that introduces a "magic number" (so not such a good idea).

C++ std::map key sort comparison function?

I have a class where I overload all the comparison operators. I load a bunch of these objects into a map as keys and I expect the map to sort them least to greatest.
However, the map is actually sorted by greatest to least. Why is this? Does it not use the comparison operators on the key when it sorts the map? How can I make it do this?
If you look at the definition for std::map, the 3rd parameter is the comparator - std::less< Key > by default. The default implementation of which is just to invoke operator<.
You could try defining a new version in the header where YourType is defined, like so:
template<> std::less< YourType >
{
bool operator()(
const YourType& lhs,
const YourType& rhs)
{
if(!(lhs.member1 < rhs.member1))
{
return false;
}
if(!(lhs.member2 < rhs.member2))
{
return false;
}
return true;
}
}
Remember to friend std::less< YourType > in your class.
The actual test must comply with the following or you'll get all kinds of problems:
lhs < rhs = true
rha < lhs = false
lhs < lhs = false
One important thing to note (that I discovered quite recently) is that if your compiler starts complaining that you've redefined the meaning of std::less or other funky things, it could be that you've only forward declared your YourType when you declared your std::map< YourType >.
Hope this helps!
You should post your code that implements the overload of the comparison operators, so may answer is based on guessing:
Your problem could be a simple typo (I did that once)
bool operator < ( T lhs, T rhs ) const
{
return rhs < lhs; // note: lhs is on the right!
}
but actually you want:
bool operator < ( T lhs, T rhs ) const
{
return lhs < rhs;
}

How should I compare pairs of pointers (for sort predicate)

I have a STL container full of billions of the following objects
pair<SomeClass*, SomeClass*>
I need some function of the following form
/*returns items sorted biggest first */
bool sortPredicate (pair<SomeClass*, SomeClass*>two, pair<SomeClass*, SomeClass*> one)
{
return ???;
}
Is there some trick I can use to very quickly compare pairs of pointers?
Edit 1: A clarification
In the end I just want to sort the list of pointer-pairs such that all of the duplicates are next to each other. Assume that there is no clear method in SomeClass that can be used for this purpose---I only have pointer pairs, and I want to find all identical pairs (in parallel). I thought a sort would do the trick, but if you can think of a better parallel method, let me know.
Edit 2: A clarification
Fixed my code (the arguments to the sort predicate were wrong--they should be pairs).
It is a quirk of C++ that arbitrary pointers of the same type are not (necessarily) comparable with <, but are comparable with std::less.
Unfortunately, the operator< for std::pair is defined in terms of operator< on the components, not std::less.
So, assuming that you want two pairs to fall in the same sort position if and only if they point to the same two objects, you need:
// "less than"
template<typename T>
bool lt(const T &lhs, const T &rhs) {
return std::less<T>()(lhs, rhs);
}
typedef std::pair<SomeClass*, SomeClass*> mypair;
bool sortPredicate(const mypair &lhs, const mypair &rhs) {
return lt(lhs.first, rhs.first)
|| (!lt(rhs.first, lhs.first) && lt(lhs.second, rhs.second));
}
On pretty much any system you can name, this should compile to the same code as return lhs < rhs;, but that is not formally correct. If the referands of the pointers are all subobjects of the same object (for instance if you have a huge array and all the pairs point to elements of that one array), then operator< is OK for the pointers and hence OK for std::pair<pointer,pointer>.
If you want to pairs to fall in the same sort position if and only if the objects they point to sort the same, then you'd add the extra dereference:
bool sortPredicate(const mypair &lhs, const mypair &rhs) {
return lt(*lhs.first, *rhs.first)
|| (!lt(*rhs.first, *lhs.first) && lt(*lhs.second, *rhs.second));
}
and perhaps you'd also add checks for null pointers, if those are permitted. Of course if you know that SomeClass really is a class type, not a pointer type, then you don't need to use std::less in the version above, just define operator< for SomeClass and:
inline bool lessptr(const SomeClass *lhs, const SomeClass *rhs) {
if (lhs == 0) return rhs != 0;
if (rhs == 0) return false;
return *lhs < *rhs;
}
bool sortPredicate(const mypair &lhs, const mypair &rhs) {
return lessptr(lhs.first, rhs.first)
|| (!lessptr(rhs.first, lhs.first) && lessptr(lhs.second, rhs.second));
}
You may or may not be able to optimise that a bit, since there are some repeated null checks performed in both the first and second calls to lessptr. If you care that much, see what the compiler does with it.
Assuming your class has comparison operators:
bool sortPredicate (SomeClass *two, SomeClass *one)
{
return *two > *one;
}
If you just want to compare the pointer addresses, use std::greater<T>:
sort(container.begin(), container.end(), std::greater<SomeClass *>());
EDIT: OK, I really have no idea what you are trying to do now, with your most recent edit. Why not just use the default sort, if all you want to do is find duplicates?
If I understand correctly Your predicate should have the following signature
bool sortPredicate(pair<SomeClass*, SomeClass*>& lhs, pair<SomeClass*, SomeClass*>& rhs);
I know nothing about Your class and if there is any natural order for it, so it's hard to guess how You want to sort it. In The comment You write that the biggest items should be first. I assume there is < operator for the class. How about this?
bool sortPredicate(pair<SomeClass*, SomeClass*>& lhs, pair<SomeClass*, SomeClass*>& rhs)
{
if(!(*(lhs.first) < *(rhs.first) || *(rhs.first) < *(lhs.first))) // If there is == operator use it.
{
return *(rhs.second) < *(lhs.second);
}
else
{
return *(rhs.first) < *(lhs.first);
}
}
EDIT: Ok thx for clarifying. How about this?
bool sortPredicate(pair<SomeClass*, SomeClass*>& lhs, pair<SomeClass*, SomeClass*>& rhs)
{
if(lhs.first == rhs.first)
{
return rhs.second < lhs.second;
}
else
{
return rhs.first < lhs.first;
}
}
You should define an operator<on your pair class. I assume that your pair holds item1 and item2. So:
template <class T>
class pair{
private:
T item1;
T item2
public:
// [...] other stuff goes here
// here the comparing
bool operator<(pair p){
return (item1 < p.item1 || (item1 == p.item1 && item2 < p.item2));
}
};
This solution assumes that the items have defined the < and the == operators.
I suppose I didn't meet what you were exactly looking for, but I recommend to overload the <, >, and == operators in your pair class.