Pedantic gcc warning: type qualifiers on function return type

C++ConstantsGcc Warning

C++ Problem Overview


When I compiled my C++ code with GCC 4.3 for the first time, (after having compiled it successfully with no warnings on 4.1, 4.0, 3.4 with the -Wall -Wextra options) I suddenly got a bunch of errors of the form warning: type qualifiers ignored on function return type.

Consider temp.cpp:

class Something
{
public:
    const int getConstThing() const {
        return _cMyInt;
    }
    const int getNonconstThing() const {
        return _myInt;
    }

    const int& getConstReference() const {
        return _myInt;
    }
    int& getNonconstReference() {
        return _myInt;
    }

    void setInt(const int newValue) {
        _myInt = newValue;
    }

    Something() : _cMyInt( 3 ) {
        _myInt = 2;
    }
private:
    const int _cMyInt;
    int _myInt;
};

Running g++ temp.cpp -Wextra -c -o blah.o:

temp.cpp:4: warning: type qualifiers ignored on function return type
temp.cpp:7: warning: type qualifiers ignored on function return type

Can someone tell me what I am doing wrong that violates the C++ standard? I suppose that when returning by value, the leading const is superfluous, but I'm having trouble understanding why it's necessary to generate a warning with it. Are there other places where I should leave off the const?

C++ Solutions


Solution 1 - C++

It doesn't violate the standard. That's why they're warnings and not errors.

And indeed you're right — the leading const is superfluous. The compiler warns you because you've added code that in other circumstances might mean something, but in this circumstance means nothing, and it wants to make sure you won't be disappointed later when your return values turn out to be modifiable after all.

Solution 2 - C++

I encountered this warning when compiling some code that uses Boost.ProgramOptions. I use -Werror so the warning was killing my build, but because the source of the warning was in the depths of Boost I couldn't get rid of it by modifying my code.

After much digging I found the compiler option that disables the warning:

-Wno-ignored-qualifiers

Hope this helps.

Solution 3 - C++

Returning a constant value only makes sense when you return a reference or a pointer(in this case pointer to constant and not a constant pointer) because the caller is able to modify the referenced (pointed to) value.

Another comment on the code not related to your question: I think it's better to use a setter instead of

int& getNonconstReference() {
    return _myInt;
}

Which will should be:

void setMyInt(int n) {
  _myInt = n;
}

Moreover, it's useless to return a const reference to an int. It does make sense for a bigger object whose copy or move is more expensive.

Solution 4 - C++

Having this

struct Foo { Foo(int) {} operator bool() { return true; } };

and that

Foo some_calculation(int a, int b) { Foo result(a + b); /*...*/ return result; }

the example

if (some_calculation(3, 20) = 40) { /*...*/ }

compiles without a warning. Of course, this is rare. But isn't const correctness about making it hard for people to do things wrong? And with the expectation that people try things, that are wrong, the return type should be declared const. And: g++ warns about ignoring the classifier, but does not ignore it. I think, the warning is about users that take the copy and ignore the const classifiers on their copy. But that should not be a warning, because this is absolutely correct behavior. And it makes sense to do this.

Solution 5 - C++

Shouldn't -pedantic only allow strict adherence to the ISO standard? Depending on -std= of course...

Solution 6 - C++

This warning is also useful to avoid confusion when declaring functions returning pointers to objects which should not be modified:

// "warning: type qualifiers ignored on function return type"
// as the pointer is copied. 
Foo* const bar();

// correct:
const Foo* bar();

Solution 7 - C++

There is a difference between const on a basic type result, where it's ignored, and const on a class type result, where it generally wreaks havoc.

namespace i {
    auto f() -> int const { return 42; }
    void g( int&& ) {}
}

namespace s {
    struct S {};
    auto f() -> S const { return {}; }
    auto g( S&&  ) {}
}

auto main() -> int
{
    { using namespace i; g( f() ); }    // OK
    { using namespace s; g( f() ); }    // !The `const` prevents this.
}

This is why the compiler warns in the first case: it's a special case, that may not do what one naïvely could expect.

For modern programming it would IMHO be nice also with a warning about const on class type result, since it prohibits move semantics; a rather severe cost for whatever little advantage one envisioned.

Solution 8 - C++

Scott Meyers pointed out that there's pretty good reason why someone would want to return const values. Here's an example:

int some_calculation(int a, int b) { int res = 0; /* ... */ return res; }

/* Test if the result of the calculation equals 40.*/
if (some_calculation(3,20) = 40)
{

}

Do you see what I did wrong? This code is absolutely correct and should compile. The problem is that the compiler didn't understand that you intended tocompare instead of assign the value 40.

With a const return value the above example won't compile. Well, at least if the compiler doesn't discard the const keyword.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSeth JohnsonView Question on Stackoverflow
Solution 1 - C++Rob KennedyView Answer on Stackoverflow
Solution 2 - C++ccaughieView Answer on Stackoverflow
Solution 3 - C++BrahimView Answer on Stackoverflow
Solution 4 - C++mcbulbaView Answer on Stackoverflow
Solution 5 - C++SteveView Answer on Stackoverflow
Solution 6 - C++LuchsView Answer on Stackoverflow
Solution 7 - C++Cheers and hth. - AlfView Answer on Stackoverflow
Solution 8 - C++user321269View Answer on Stackoverflow