Why does this compiler warning only show for int but not for string? "type qualifiers ignored on function return type"

Viewed 112

I am a bit confused about some warnings I get when compiling my C++11 code using mingw64. This is my MWE:

class A{
    const string name;
    const int ID;

    public:
        A(string name_, int ID_) : name(name_), ID(ID_){
            // initialize non-const members
        }
        const string getName() const{return name;}
        const int getID() const{return ID;}
};

int main()
{   
    A aObj = A("Aname", 1);
    std::cout << "getName() = " << aObj.getName() << std::endl;
    std::cout << "getID() = " << to_string(aObj.getID()) << std::endl;
}

Code executes fine and does what it should, but I get this compiler warning:

,,localtest.cpp:10:9: warning: type qualifiers ignored on function return type

[-Wignored-qualifiers] const int getID() const{return ID;}

So the warning only shows for getID() but not for getName(), even though both have the same type qualifiers. Can somebody explain to me, why this warning seems only to show for string but not for int? I suppose it has something to do with int being a primitive data type - but what exactly?

4 Answers

std::string is a class that has member functions that can be constant. If you have a constant object of the class you may apply only constant member functions.

As for fundamental types like for example int then the qualifier const does not make a sense for a return value because in any case you can not change the returned value.

Here is a demonstrative program

#include <iostream>
#include <string>

template <typename T>
const T f( const T &t )
{
    return t;
}

int main() 
{
    std::cout << f( std::string( "Hello World!" ) ).length() <<  '\n';

//  Invalid assignment  
//  f( 10 ) = 20;
    
    return 0;
}

The program output is

12

As you can see you can apply constant member functions to the returned object of the type std::string (but you can not apply non-constant member functions). And you can not change the returned value of the type int.

Consider the following:

struct MyType {
  void foo() const;
  void bar();
};

MyType getMutable();
const MyType getConst();

int main() {
  getMutable().foo(); // fine
  getMutable().bar(); // fine
  getConst().foo(); // fine
  getConst().bar(); // Not allowed!
}

There just isn't anything equivalent for int. The set of operations you can do on a int RValue is the exact same as for a const int RValue. That's why you are getting a redundancy warning.

See [expr.type]:

If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.

The essence is: you can have expressions of const class or array types, but not of const primitive types.

Since int is not a class, it is enough for return type to be rvalue to prevent any and all modifications of the returned object. Thus,

getInt(20) = 500;

would not be compilable code, and there are no members you could invoke on objects of int type. This is why const-qualifying built-in types as return values make no sense, and compiler is warning you about that.

But the situation is different for the classes.

getString("string").clear();

Might be either valid or invalid code, based on whether getString returns non-const or const std::string object, thus compiler is not issuing a warning in the latter case.

Related