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.
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;
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 );
I am trying to make a program that demonstrates use of templates and overloaded operators for my CS class. Here is relevant code:
main:
ArrayTemplate<int> number(0);
number[0] = 1;
number[1] = 2;
number[2] = 3;
ArrayTemplate<string> word("na");
word[0] = "One";
word[1] = "Two";
word[2] = "Three";
header:
template<class T>
T& operator [](const int index)
{
if(index >= 0 && index < ARRAY_MAX_SIZE)
return items[index];
else
{
cerr << "INDEX OUT OF BOUNDS!!!";
exit(1);
}
}
The problem is that when I try to use my overloaded subscript operator I get the error message shown in title: "No such operator "[]" matches these operands" Im not exactly sure why. It does it for both my integer array and my string array. Any help is appreciated.
You really need to show the full definition of ArrayTemplate.
This is how you probably want it to look:
template<class T>
class ArrayTemplate {
public:
// ...
T& operator [](const int index)
{
if(index >= 0 && index < ARRAY_MAX_SIZE)
return items[index];
else
{
cerr << "INDEX OUT OF BOUNDS!!!";
exit(1);
}
}
// ...
};
Note that operator[] isn't templated; only the class is.
With your current code you would have to do it like this:
number<int>[0] = 1;
number<int>[1] = 2;
number<int>[2] = 3;
Which obviously goes against your intention.
template<class T>
T& operator [](const int index)
This declaration would be called e.g. as object.operator[] < type >( 5 ). Note that type needs to be provided as a template argument. Because there's no way to supply such an argument in an expression using [], the operator overload doesn't work.
Probably you don't want the template< class T > at all. Just get rid of it:
T& operator [](const int index)
If you define the function outside the class {} scope, then it would look like this:
template<class T>
T& ArrayTemplate<T>::operator [](const int index)
In this case, the template<class T> line re-introduces the parameter in order to get back into the class template.
I have a class, and the pointers to the objects of this class need to be placed in a std::set. I want to define the comparator inside the class. I have seen a few solutions where either a separate class is defined (I guess it is called a functor), or a structure is defined which overloads the operator(). I want to avoid this boilerplate code, and want to define a comparator as a member of the class itself, something along the lines of Java's compareTo() method.
Let us say, my class is something like:
class Item {
private:
int id;
float score;
.....
public:
// Rest of the methods and setters/getters
}
I want to define the comparator in a way that pointer to object having a higher score are placed first in the set. If the score is equal for the two, then the one with the lower id is placed first. I guess the code will be something like the following, but since I did not understand this part very well, please correct me (I would like this to be placed inside the class itself):
bool operator()(const Item* a, const Item* b) {
if (a->score != b->score) return a->score > b->score;
return a->id < b->id;
}
The usage would be as follows:
std::set<Item*> sortedItems;
Item* item = new Item();
sortedItems.insert(item);
I am not sure if the comparator needs to be specified at all in the std::set template if defined within the class, and if so, how? Also, how do I add this comparator in the class itself? I am new to STL, and fairly new to C++ as well. Thanks!
this solution is inspired by this answer.
#include <set>
class Item {
private:
int id;
float score;
public:
struct compare {
bool operator()(const Item* a, const Item* b) {
if (a->score != b->score) return a->score > b->score;
return a->id < b->id;
}
};
};
Because set allows you to define your own comparison method you can use it as follows.
std::set<Item*, Item::compare> sortedItems;
This should allow your class Item to work with set
The set<T> implementation wants to call a < b where a and b are objects of type T. As long as that call is valid, the set doesn't care; it can be a non-static member function that takes one argument, a static member function that takes two arguments, or a free function that takes two argument:
class Item {
public:
bool operator<(const Item& rhs) {
return score == rhs.score ? id < rhs.id : score < rhs.score;
}
static bool operator<(const Iterm& lhs, const Item& rhs) {
return lhs.score == rhs.score ? lhs.id < rhs.id : lhs.score < rhs.score;
}
};
bool operator<(const Item& lhs, const Item& rhs) {
return lhs.score == rhs.score ? lhs.id < rhs.id : lhs.score < rhs.score;
}
Any one of those three is okay. Of course, if you write two or more of them, you'll get ambiguities.
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.