c++member-functionsconst-correctnessstdsetfunction-qualifier

error: passing const xxx as 'this' argument of member function discards qualifiers


#include <iostream>
#include <set>

using namespace std;

class StudentT {

public:
    int id;
    string name;
public:
    StudentT(int _id, string _name) : id(_id), name(_name) {
    }
    int getId() {
        return id;
    }
    string getName() {
        return name;
    }
};

inline bool operator< (StudentT s1, StudentT s2) {
    return s1.getId() < s2.getId();
}

int main() {

    set<StudentT> st;
    StudentT s1(0, "Tom");
    StudentT s2(1, "Tim");
    st.insert(s1);
    st.insert(s2);
    set<StudentT> :: iterator itr;
    for (itr = st.begin(); itr != st.end(); itr++) {
        cout << itr->getId() << " " << itr->getName() << endl;
    }
    return 0;
}

In line:

cout << itr->getId() << " " << itr->getName() << endl;

It give an error that:

../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers

../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers

What's wrong with this code?


Solution

  • The objects in the std::set are stored as const StudentT. So when you try to call getId() with the const object the compiler detects a problem, mainly you're calling a non-const member function on const object which is not allowed because non-const member functions make NO PROMISE not to modify the object; so the compiler is going to make a safe assumption that getId() might attempt to modify the object but at the same time, it also notices that the object is const; so any attempt to modify the const object should be an error. Hence compiler generates an error message.

    The solution is simple: make the functions const as:

    int getId() const {
        return id;
    }
    string getName() const {
        return name;
    }
    

    This is necessary because now you can call getId() and getName() on const objects as:

    void f(const StudentT & s)
    {
         cout << s.getId();   //now okay, but error with your versions
         cout << s.getName(); //now okay, but error with your versions
    }
    

    As a sidenote, you should implement operator< as :

    inline bool operator< (const StudentT & s1, const StudentT & s2)
    {
        return  s1.getId() < s2.getId();
    }
    

    Note parameters are now const reference.