I ran into a problem.
I have a class A,and a class that inherits from A,lets call it class B.
I have virtual functions.
I want to compare A and B to another class C by operator==.
If i want to have a list of A's,lets say in stl list,
I must use a pointer to A,so it will look like:
list<*A> list;
and also i have: C something
but now,i cant use the function:find(list.begin(),list.end(),something)
because i cant use operator == for pointers(*).
I found a solution but i dont think its the best,so my question is-can i do it better?
iter=list.begin();
for(iter;iter!=list.end();++iter)
{
if((*iter).operator==(something)
return ...
}
Thank you.
You could use find_if, which lets you provide a function to check for equal values.
auto check_something =
[&something](const list<*A>::iterator& iter){return *iter == something; };
find_if(list.begin(),list.end(),check_something)
You can use
if(**iter == something)
if you want to dereference the pointer.
In C++1x, there is also
for(auto ptr : list)
if(*ptr == something)
Nothing says you can't make a global non-member operator == that operates on pointers or combinations of pointers and objects. If you have many types you could template the combination of pointer vs object equality for any type.
Edit to add this tip: Put the comparison in a namespace with your objects and then argument dependent lookup will find it without putting a global T* == T in scope that catches everything:
namespace equals {
struct A {
A(int x) :x(x) { }
bool operator == (const A &other) const {
return other.x == x;
}
int x;
};
template <typename T>
bool operator == (const T *lhs, const T &rhs) {
return *lhs == rhs;
}
template <typename T>
bool operator == (const T &lhs, const T *rhs) {
return lhs == *rhs;
}
}
Now you can do things like:
equals::A b(1), c(1);
if (b == &c) std::cerr << "good!" << std::endl;
You might have a look at boost::indirect_iterator which is designed for just this purpose.
find(
boost::make_indirect_iterator( list.begin() ),
boost::make_indirect_iterator( list.end() ),
something );
Related
I have the following struct
struct MyClass {
int myInt;
std::map<int, int> myMap;
};
I want to use unordered_set<MyClass*, PointedObjHash, PointedObEq> but I can't find a valid way to declare PointedObEq.
I tried
struct PointedObjHash {
size_t operator() (MyClass* const& c) const {
std::size_t seed = 0;
boost::hash_combine(seed, c->myInt);
boost::hash_combine(seed, c->myMap);
return seed;
}
and I hope it is fine, but I can't find a way to declare PointedObjEq
--- EDIT ---
If declare operator== inside the class debug never breaks, but I think 'cause MyClass == MyClass* never happens...
struct MyClass {
...
...
bool operator==(MyClass* const& c) {
return this->myInt == c->myInt & this->myMap == c->myMap;
}
If declare operator== inside the class debug never breaks, but I think 'cause MyClass == MyClass* never happens...
The unordered_set needs to use operator== (or PointedObjEq) to double-check the results of the hash function. The hash provides approximate equality, the equality function is used to weed out false positives.
If you've tested adding the same value to the set twice, then you've tested the equality function. To be sure, of course, you can have it print something to the console.
Since it's impossible to define an operator== function with two pointer operands, the PointedObjEq class will be necessary. Note that it takes a MyClass const * on both sides. Also, there's no need to use a reference to a pointer.
So,
struct PointedObjEq {
bool operator () ( MyClass const * lhs, MyClass const * rhs ) const {
return lhs->myInt == rhs->myInt
&& lhs->myMap == rhs->myMap;
}
};
This should do:
struct PointedObEq {
bool operator()(MyClass const * lhs, MyClass const * rhs) const {
return lhs->myInt == rhs->myInt && lhs->myMap == rhs->myMap;
}
};
The reason why your solution does not work is because you have effectively written a mechanism to compare a MyClass with a MyClass*, when you actually need something to compare a MyClass* with a MyClass*.
P.S.: My original answer passed the pointers by const&. Thinking about it, that's a strange coding style, so I changed it to pass the pointers by value.
typedef MyClass* PtrMyClass;
struct PointedObjCompare
{ // functor for operator==
bool operator()(const PtrMyClass& lhs, const PtrMyClass& rhs) const
{
// your code goes here
}
};
std::unordered_set < MyClass*, PointedObjHash, PointedObjCompare > myset;
Quite often I have two variables foo1 and foo2 which are numeric types. They represent the bounds of something.
A user supplies values for them, but like a recalcitrant musician, not necessarily in the correct order!
So my code is littered with code like
if (foo2 < foo1){
std::swap(foo2, foo1);
}
Of course, this is an idiomatic sort with two elements not necessarily contiguous in memory. Which makes me wonder: is there a STL one-liner for this?
I suggest to take a step back and let the type system do the job for you: introduce a type like Bounds (or Interval) which takes care of the issue. Something like
template <typename T>
class Interval {
public:
Interval( T start, T end ) : m_start( start ), m_end( end ) {
if ( m_start > m_end ) {
std::swap( m_start, m_end );
}
}
const T &start() const { return m_start; }
const T &end() const { return m_end; }
private:
T m_start, m_end;
};
This not only centralizes the swap-to-sort code, it also helps asserting the correct order very early on so that you don't pass around two elements all the time, which means that you don't even need to check the order so often in the first place.
An alternative approach to avoid the issue is to express the boundaries as a pair of 'start value' and 'length' where the 'length' is an unsigned value.
No, but when you notice you wrote the same code twice it's time to write a function for it:
template<typename T, typename P = std::less<T>>
void swap_if(T& a, T& b, P p = P()) {
if (p(a, b)) {
using std::swap;
swap(a, b);
}
}
std::minmax returns pair of smallest and largest element. Which you can use with std::tie.
#include <algorithm>
#include <tuple>
#include <iostream>
int main()
{
int a = 7;
int b = 5;
std::tie(a, b) = std::minmax({a,b});
std::cout << a << " " << b; // output: 5 7
}
Note that this isn't the same as the if(a < b) std::swap(a,b); version. For example this doesn't work with move-only elements.
if the data type of your value that you're going to compare is not already in c++. You need to overload the comparison operators.
For example, if you want to compare foo1 and foo2
template <class T>
class Foo {
private:
int value; // value
public:
int GetValue() const {
return value;
}
};
bool operator<(const Foo& lhs, const Foo& rhs) {
return (lhs.GetValue() < rhs.GetValue());
}
If your value is some type of int, or double. Then you can use the std::list<>::sort member function.
For example:
std::list<int> integer_list;
int_list.push_back(1);
int_list.push_back(8);
int_list.push_back(9);
int_list.push_back(7);
int_list.sort();
for(std::list<int>::iterator list_iter = int_list.begin(); list_iter != int_list.end(); list_iter++)
{
std::cout<<*list_iter<<endl;
}
I am trying to understand operators you need to overload when working with custom classes in STL(SCL).
Can any one please tell me what is it I am doing wrong ?
class myClass
{
public:
int data;
myClass()
{
data =0;
cout<<"Default const "<<endl;
}
myClass(int x)
{
data = x;
cout<<"Int constructor"<<endl;
}
myClass(const myClass &m)
{
cout<<"Copy constructor"<<endl;
}
bool operator == (const myClass &temp)
{
cout<<"Operator called &";
return data == temp.data;
}
bool operator == (const myClass *temp)
{
cout<<"Operator called *";
return data == temp->data;
}
};
int main ()
{
/*
vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(30);
cout << "myvector contains:";
for_each (myvector.begin(), myvector.end(), meObj);
*/
vector<myClass*> myVec;
myClass temp;
myVec.push_back(&temp);
myClass temp2(19);
myVec.push_back(&temp2);
myClass temp3(19);
vector<myClass*>::iterator it = find(myVec.begin(),myVec.end(),&temp2); //works
if(it!=myVec.end())
{
cout<<"Value is "<<(*it)->data;
}
vector<myClass*>::iterator dit = find(myVec.begin(),myVec.end(),&temp3); //fails
if(dit!=myVec.end())
{
cout<<"Value is "<<(*dit)->data;
}
cout << endl;
return 0;
}
Please correct me if I am wrong, but the first find works as it does a address comparison. What do I need to overload for the above to work ?
Do both the signature make sense ?
bool operator == (const myClass &temp); // seen in many places
bool operator == (const myClass *temp); // what if two pointer types of same object are being compared?
Cheers!
Operator overloads must have at least one user-defined type. So you cannot overload operator== for two pointers, for instance.
Your myClass::operator==(const myClass *temp) is valid in the sense that it compiles, but makes very little semantic sense, and is not recommended (there are very few situations where you'd want to do T x; T *y; ... (x == y)).
For your situation, where you have a vector of pointers, you may want to consider std::find_if, which takes a predicate. Something like:
class CompareByPointer
{
public:
explicit CompareByPointer(const myClass &p) : p(p) {}
bool operator() (const myClass &rhs) const { return p->data == rhs->data; }
private:
const myClass &p;
};
...
find_if(myVec.begin(), myVec.end(), CompareByPointer(&temp2));
[As a side note, you should generally define member functions const wherever possible. So your operator overloads should be const.]
In the sample code, you haven't pushed &temp3 into myVec. So it makes sense for the second std::find to fail.
What do you mean by "work" in this case? Generally, when you're storing pointers, it's because the objects do have identity, and comparing the address is the correct thing to do. Otherwise, you should probably be storing values (although there are exceptions). Anyway, you can always use find_if, and any comparison criteria you want. For anything but the simplest types, I find myself using find_if more often than find anyway; usually, you're not looking for equality, but rather for some specific type of match. Here, for example, you'd more likely want something like:
std::vector<MyClass>::iterator it = std::find_if( myVect.begin(), myVect.end(),
boost::bind(&MyClass::id, _1, 19) );
(Supposing that the data here is some sort of identifier, and that you've provided a member function, myClass::id() to read it.)
I have a problem with the operator < that i wrote:
in Node.h :
.
..
bool operator<(const Node<T>& other) const;
const T& GetData ();
.
..
template <class T>
const T& Node<T>::GetData () {
return m_data;
}
template <class T>
bool Node<T>:: operator<(const Node<T>& other) const
{
return (*(this->GetData()) < *(other.GetData()));
}
in Heap.h :
template<class T>
void Heap<T>::Insert(Node<T>* newNode) {
if (m_heap.size() == 0) {
m_heap.push_back(newNode);
}
else
DecreaseKey(newNode);
}
template<class T>
void Heap<T>::DecreaseKey(Node<T>* newNode) {
m_heap.push_back(newNode);
int index = m_heap.size();
while ((index > 1) && (m_heap[(index/2)-1] < (m_heap[index-1]))) { // doen't do the operator < !
Exchange(index,index/2);
index = index/2;
}
}
in Vehicle.h:
bool operator< (const Vehicle& otherVehicle) const;
in Vehicle.cpp:
bool Vehicle::operator<(const Vehicle& otherVehicle) const {
return (GetDistance() > otherVehicle.GetDistance());
}
in main.cpp:
.
..
Node<Vehicle*> a(car1);
Node<Vehicle*> b(car2);
Heap<Vehicle*> heap;
Node<Vehicle*>* p = &a;
Node<Vehicle*>* q = &b;
heap.Insert(p);
heap.Insert(q);
heap.ExtractMin()->GetData()->Show();
.
..
Why it doen't do the compeare ? with opeartor < , note: it pass the compiler.
m_heap is a container of pointers. In this case you should dereference the node pointers:
while ((index > 1) && (*m_heap[(index/2)-1] < (*m_heap[index-1])))
This should now call operator< for Nodes, which in turn calls operator< for Vehicles.
Because you used Vehicle*, not Vehicle.
Use std::priority_queue instead of Heap, or any other heap that allows you to define custom comparison predicate.
From what I see m_heap stores pointer to Node
while ((index > 1) && (m_heap[(index/2)-1] < (m_heap[index-1]))) { // doen't do the operator <
I guess this should do
while ((index > 1) && (*(m_heap[(index/2)-1]) < *(m_heap[index-1]))) {
Short answer: don't use pointers. You probably don't need them.
If possible, it's much easier to get this kind of code correct if you use plain objects. If you need to use the concept of a pointer, use a pointer-container class, i.e. a wrapper that is passed around as a plain object with value semantics and potentially custom overloads such as the operator< you're using, but which hides the implementation pointer internally.
That way, you don't need to deal with pointers all over your app, but only where semantically relevant.
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.