迂腐的 gcc 警告: 函数返回类型的类型限定符

当我第一次用 GCC 4.3编译我的 C + + 代码时(在使用 -Wall -Wextra选项在4.1,4.0,3.4上没有警告的情况下成功地编译了它之后) ,我突然发现了一堆 warning: type qualifiers ignored on function return type格式的错误。

考虑 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;
};

运行 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

谁能告诉我哪里做错了,违反了 C + + 标准?我认为当按值返回时,前面的 const是多余的,但是我很难理解为什么需要用它来生成警告。还有其他地方我应该停止使用常数吗?

85414 次浏览

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.

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.

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.

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.

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

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();

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.

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.