Reputation: 91
I try to use a std::set
in order to have unique elements in my container.
Since I have 3D objects :
Class Object3D{
private:
float x;
float y;
float z;
}
Those objects are equal when (A.x==B.x && A.y==B.y && A.z==B.z)
.
In std::set implementation a element A==B if (!(A < B) && !(B>A))
.
It's impossible for my comparison... I have tried to overload ==
operator.
I chose set container for comparing values when I call insert(a)
.
I was doing something like that with std::vector v
and his iterator:
if(!(A).inVector()){
v.push_back(A);
}
With
bool inVector(){
for(itr = v.begin();itr != v.end();itr++){
if(this->x==(*itr)->x && this->y==(*itr)->y && this->z==(*itr)->z){
return true;
}
}
return false;
}
Checking it for each object (10000-100000) is expensive in complexity.
Can someone have an idea ?
Upvotes: 8
Views: 7816
Reputation: 103693
You need to provide a comparator. You don't want to implement operator<
, and I agree with that decision. You shouldn't provide meaningless functions for your class just to satisfy the constraints of some container. Thankfully, you don't need operator<
. But you do need a function that has behavior similar to operator<
. It doesn't have to mean that one object is considered less than another. It just needs to provide a strict-weak ordering. You can give it any name you want. For example:
bool Compare_by_x_then_y_then_z(const Object3D& lhs, const Object3D& rhs)
{
if (lhs.getX() != rhs.getX()) return lhs.getX() < rhs.getX();
if (lhs.getY() != rhs.getY()) return lhs.getY() < rhs.getY();
return lhs.getZ() < rhs.getZ();
}
You then provide this function to the constructor of your set:
typedef bool(*compT)(const Object3D&, const Object3D&);
std::set<Object3D,compT> objects(Compare_by_x_then_y_then_z);
Upvotes: 2
Reputation: 6999
You have to provide a comparison operator, because std::set
needs it for its implementation.
A simple less-than operator would look like this:
bool Object3D::operator<(const Object3D& other) const {
if(x != other.x) return x < other.x;
if(y != other.y) return y < other.y;
return z < other.z;
}
Upvotes: 1
Reputation: 67723
@OP: std::set
is a unique, ordered container. It requires either an operator<
or a comparator passed explicitly, which implements a strict weak ordering.
If you don't want to impose an ordering on your elements, don't use an ordered container. You can use std::unordered_set
if you just want to detect uniqueness without imposing an ordering.
Upvotes: 5
Reputation: 476990
You need to implement a strict weak ordering <
for your class. The easiest way is to use the lexicographic ordering provided by tuple
:
#include <tuple>
class Object3D
{
public:
bool operator<(Object3D const & rhs) const
{
return std::tie(x, y, z) < std::tie(rhs.x, rhs.y, rhs.z);
}
// ...
};
Upvotes: 7
Reputation: 8027
You must declare operator<. You can do it like this
bool operator<(const Object3D& a, const Object3D& b)
{
if (a.x < b.x) return true;
if (b.x < a.x) return false;
if (a.y < b.y) return true;
if (b.y < a.y) return false;
if (a.z < b.z) return true;
if (b.z < a.z) return false;
return false;
}
It is arbitrary, but it doesn't really matter. As long as operator< gives a consistent ordering you'll be OK.
Upvotes: 1