JP King
JP King

Reputation: 13

Overloading extraction operator for a custom class set

I've made a custom class user, and made a set<user> users in another class dbase. I've successfully overloaded the extraction operator for the class user and now I'm trying to overload the extraction operator for the class dbase.

This is my code:

ostream& operator<< (ostream &out, dbase &db) {
    set<user>::iterator it;
    for(it=db.users.begin(); it!=db.users.end(); it++)
        out<<(*it)<<endl;    //error reported on this line
    return out;
}

But I keep on getting this error:

error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

This is the operator<< declaration of class user:

ostream& operator<<(ostream &out, user &u) {
    cout<<endl;
    cout<<"Username: "<<u.uname;
    cout<<endl;
    return out;
}

Here is the complete code: (ideone)

#include <iostream>
#include <set>
#include <string>
#include <sstream>
using namespace std;

template <class T>
string to_string(T x) {
    stringstream ss;
    ss<<x;
    return ss.str();
}

class date {
    int dd,mm,yyyy;
    string str_date;
    public:
        string get_date() {
            return to_string(dd)+"-"+to_string(mm)+"-"+to_string(yyyy);
        }
        friend ostream& operator << (ostream&,date&);
        friend istream& operator >> (istream&,date&);
};

ostream& operator<< (ostream &out, date &d) {
    out<<d.get_date();
    return out;
}

istream& operator>> (istream &in, date &d) {
    cin>>d.dd>>d.mm>>d.yyyy;
    return in;
}

class user {
    string uname, pwd;
    string full_name, contact;
    static unsigned long long int id;
    date dob;

    public:
        bool operator < (const user &u) const {
            if(uname.compare(u.uname)<0) return true;
            return false;
        }
        void set_uname(string u) {
            uname = u;
        }
        void set_attrib() {
            string temp_pass;
            while(1) {
                cout<<"Full Name: ";
                cin>>full_name;
                cout<<"Password: ";
                cin>>temp_pass;
                cout<<"Confirm Password: ";
                cin>>pwd;
                if(pwd.compare(temp_pass))
                    cout<<"Passwords do not match. Try Again."<<endl;
                else break;
            }
            cout<<"Contact Number: ";
            cin>>contact;
            cout<<"Date of Birth(dd mm yyyy): ";
            cin>>dob;
        }
        friend ostream& operator<<(ostream&, user&);
};

ostream& operator<<(ostream &out, user &u) {
    cout<<endl;
    cout<<"Username: "<<u.uname;
    cout<<endl;
    return out;
}

class dbase {
    set<user> users;
    public:
        void add_user() {
            string uname;
            user u;
            while(1) {
                cout<<"Username: ";
                cin>>uname;
                u.set_uname(uname);
                if(users.find(u)==users.end()) {
                    u.set_uname(uname);
                    u.set_attrib();
                    users.insert(u);
                    break;
                }
                else
                    cout<<"Username already exists. Please try a different username."<<endl;
            }
        }
        friend ostream& operator << (ostream&, dbase&);
};

ostream& operator<< (ostream &out, dbase &db) {
    set<user>::iterator it;
    user u;
    for(it=db.users.begin(); it!=db.users.end(); it++)
        out<<(*it)<<endl;
    return out;
}

int main() {

    return 0;
}

Upvotes: 0

Views: 903

Answers (1)

Bill Lynch
Bill Lynch

Reputation: 81936

So...

Lesson 1

Please post a complete compilable example. In this case, you didn't provide enough information for us to easily debug your code.

For your particular problem, that code would probably look something like this:

#include <iostream>
#include <set>
using namespace std;

class user {
    public:
        user(int id = 0): id(id) {}
        int id;
};

class dbase {
    public:
        set<user> users;
};

bool operator<(user const & lhs, user const & rhs) {
    return lhs.id < rhs.id;
}

ostream& operator<< (ostream &out, user & user) {
    return out << "user(" << user.id << ")";
}

ostream& operator<< (ostream &out, dbase &db) {
    set<user>::iterator it;
    user u;
    for(it=db.users.begin(); it!=db.users.end(); it++)
        cout<<*it<<endl;
    return out;
}

int main() {
    dbase db;
    db.users.emplace(3);
    db.users.emplace(4);
    cout << db << endl;
}

Lesson 2

Please post the entire error message that your compiler reports. In this case, it would actually be:

se.cc: In function ‘std::ostream& operator<<(std::ostream&, dbase&)’:
se.cc:28:16: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
         cout<<*it<<endl;
                ^
In file included from /opt/gcc/4.8.1/include/c++/4.8.1/iostream:39:0,
                 from se.cc:1:
/opt/gcc/4.8.1/include/c++/4.8.1/ostream:602:5: error:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = user]’
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^

Note that I haven't edited the error message in any way. It's possible that there is additional information in the message that you're missing that could be helpful to people trying to answer your question.

Lesson 3

Instead of:

ostream& operator<< (ostream &out, user & user) { ... }

Do:

ostream& operator<< (ostream &out, user const & user) { ... }

Lesson 4

When overloading the stream exaction or stream insertion operators, you should probably never use cout or cerr. Instead, you've passed a stream object into your function. In your case, you've named it with the typical (expected) argument name of out.

So, your two stream insertion operators should have every instance of cout replaced with out.

This will cause your code to work correctly when you extend it to use things like writing the user database to a file using a fstream, or if you wanted to print a message to cerr as well.

Lesson 5

Just to note. This is an issue because *it returns a reference to a const User. So your existing operator<< overload doesn't match, because it wants a non-const version of a User.

Upvotes: 3

Related Questions