0
votes

I've got a template class containing a priority queue of other classes, I need to use the priority overloader to call the individual class overloaders to compare based on the individual classes preferences (in this case it's age, in another class it could be price.

I've got absolutely no doubt that I've implemented the operator overloading incorrect so would appreciate the advice.

For example

#include <iostream>
#include <queue>
#include <string>

using namespace std;    

class Animal {
    public:
        Animal();
        Animal(string t, int a);
        int get_age()const;
        bool operator< ( Animal& b) const;
        void display()const;
    private:
        string type;
        double age;
};

void Animal::display() const
{
    cout << "Type: " << type << "    Age: " << age;
}
int Animal::get_age() const
{
    return age;
}

Animal::Animal(){}

Animal::Animal(string t, int a)
{
    type = t;
    age = a;
}

bool Animal::operator< ( Animal& b) const
{
    return b.get_age();
}

template<typename T>
class Collection {
    public:
        Collection();
        Collection(string n, string d);
        void add_item(const T& c); 
    private:
        priority_queue <T> pets;
        string name; // Name of the collection
        string description; // Descriptions of the collection
};

template<typename T>
Collection<T>::Collection(){}

template<typename T>
Collection<T>::Collection(string n, string d)
{
    name = n;
    description = d;
}

template<typename T>
bool operator<(const T& one, const T& two) 
{
     return one.operator<(two);
}

template<typename T>
void Collection<T>::add_item(const T& c)
{
    pets.push(c);
}

int main(){
    Animal p1("Dog", 10);
    Animal p2("Cat", 5);
    Animal p3("Turtle", 24);
    Collection<Animal> P("Pets", "My Pets");
    P.add_item(p1);
    P.add_item(p2);
    P.add_item(p3);
    cout << endl;

    return 0;
}

I get this error and I'm not sure what I need to do to fix it. I've got to keep the class overloader as the single variable (Animal& b).

task.cpp: In instantiation of 'bool operator<(const T&, const T&) [with T = Animal]': c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_function.h:237:22: required from 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Animal]' c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_heap.h:310:4: required from 'void std::__adjust_heap(_RandomAccessIterator, _Distance, _Distance, _Tp, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator > >; _Distance = int; _Tp = Animal; _Compare = std::less]' c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_heap.h:442:4: required from 'void std::make_heap(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator > >; _Compare = std::less]' c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_queue.h:393:9: required from 'std::priority_queue<_Tp, _Sequence, _Compare>::priority_queue(const _Compare&, const _Sequence&) [with _Tp = Animal; _Sequence = std::vector >; _Compare = std::less]' task.cpp:57:45: required from 'Collection::Collection(std::string, std::string) [with T = Animal; std::string = std::basic_string]' task.cpp:79:43: required from here task.cpp:66:30: error: no matching function for call to 'Animal::operator<(const Animal&) const' task.cpp:66:30: note: candidate is: task.cpp:36:6: note: bool Animal::operator<(Animal&) const task.cpp:36:6: note: no known conversion for argument 1 from 'const Animal' to 'Animal&' task.cpp: In function 'bool operator<(const T&, const T&) [with T = Animal]':

2
It is written in the error message change the code to this: bool Animal::operator< ( const Animal& b) const If the parameter is not of const reference type (it was Animal&), you cannot call this operator with a const argument.Oliv

2 Answers

3
votes

Your comparison

bool Animal::operator< ( Animal& b) const
{
    return b.get_age();      // returns true always unless age == 0 
}

is no comparison and it should take a const parameter. You should have something like

bool Animal::operator< (const Animal& b) const 
                       // ^----------------------- const !
{
    return get_age() < b.get_age();
}

Btw you dont need to use a member operator< for the priority queue. Especially if you want to sort objects in different ways I would recommend to not use it, but pass a lambda to the priority_queue. See eg here for an example.

0
votes

Both of your overloads of < are problematic

bool Animal::operator< ( Animal& b) const

the Animal should also be const. You also need to compare both parameters, otherwise things (such as your priority_queue) that expect < to provide an ordering will have undefined behaviour.

You don't use anything non-public from Animal, so I suggest you change it to

bool operator< (const Animal & lhs, const Animal & rhs)
{ return lhs.get_age() < rhs.get_age(); } 

This has the benefit of treating both sides identically, rather than one being implicit.

template<typename T>
bool operator<(const T& one, const T& two) 
{
     return one.operator<(two);
}

This template matches all types and is entirely superfluous. a < b can call either a member or a free operator <. Just delete this template.