Предупреждение pedantic gcc: введите квалификаторы типа возвращаемого типа
Когда я впервые скомпилировал свой код на С++ с помощью GCC 4.3 (после того, как он скомпилировал его успешно без предупреждений на 4.1, 4.0, 3.4 с параметрами -Wall -Wextra
), я неожиданно получил кучу ошибок формы 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
Может ли кто-нибудь сказать мне, что я делаю неправильно, что нарушает стандарт С++? Я полагаю, что при возврате по значению ведущий const
лишний, но мне трудно понять, почему ему необходимо создать предупреждение. Существуют ли другие места, где я должен покинуть const?
Ответы
Ответ 1
Это не нарушает стандарт. Вот почему они являются предупреждениями, а не ошибками.
И действительно, вы правы - ведущий const
лишний. Компилятор предупреждает вас, потому что вы добавили код, который в других обстоятельствах мог бы что-то значить, но в этом случае ничего не значит, и он хочет убедиться, что позже вы не будете разочарованы, когда ваши возвращаемые значения окажутся модифицируемыми в конце концов.
Ответ 2
Я столкнулся с этим предупреждением при компиляции кода, который использует Boost.ProgramOptions. Я использую -Werror
, поэтому предупреждение убивает мою сборку, но поскольку источник предупреждения был в глубине Boost, я не мог избавиться от него, изменив свой код.
После многократного поиска я нашел параметр компилятора, который отключает предупреждение:
-Wno-ignored-qualifiers
Надеюсь, что это поможет.
Ответ 3
Возвращение постоянного значения имеет смысл только тогда, когда вы возвращаете ссылку или указатель (в этом случае указатель на константу, а не на указатель константы), поскольку вызывающий может изменить ссылочное (указанное) значение.
Еще один комментарий к коду, не относящийся к вашему вопросу:
Я думаю, что лучше использовать сеттер вместо
int& getNonconstReference() {
return _myInt;
}
Какой должен быть:
void setMyInt(int n) {
_myInt = n;
}
Кроме того, бесполезно возвращать константную ссылку на int. Это имеет смысл для более крупного объекта, чья копия или перемещение дороже.
Ответ 4
Имея это
struct Foo { Foo(int) {} operator bool() { return true; } };
и что
Foo some_calculation(int a, int b) { Foo result(a + b); /*...*/ return result; }
пример
if (some_calculation(3, 20) = 40) { /*...*/ }
компилируется без предупреждения. Конечно, это редко. Но не является ли правильность констатации для того, чтобы заставить людей делать что-то неправильно? И с ожиданием того, что люди пытаются что-то сделать, это неверно, тип возврата должен быть объявлен как const.
И: g++ предупреждает об игнорировании классификатора, но не игнорирует его. Я думаю, предупреждение о пользователях, которые берут копию и игнорируют классификаторы const на их копии. Но это не должно быть предупреждением, потому что это абсолютно правильное поведение. И имеет смысл сделать это.
Ответ 5
Нельзя ли - абхазность допускать строгое соблюдение стандарта ISO? В зависимости от -std = конечно...
Ответ 6
Это предупреждение также полезно, чтобы избежать путаницы при объявлении функций, возвращающих указатели на объекты, которые не следует изменять:
// "warning: type qualifiers ignored on function return type"
// as the pointer is copied.
Foo* const bar();
// correct:
const Foo* bar();
Ответ 7
Существует разница между const
по результату базового типа, где он игнорируется, и const
для результата типа класса, где он обычно вызывает хаос.
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.
}
Вот почему компилятор предупреждает в первом случае: это особый случай, который может не делать то, что можно было бы наивно ожидать.
Для современного программирования было бы неплохо также предупредить о const
о результате типа класса, поскольку он запрещает семантику перемещения; довольно суровая стоимость для любого небольшого преимущества, которое было предусмотрено.
Ответ 8
Scott Meyers указал, что есть довольно веская причина, почему кто-то хочет вернуть значения const
. Вот пример:
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)
{
}
Вы видите, что я сделал неправильно? Этот код абсолютно правильный и должен компилироваться. Проблема в том, что компилятор не понимал, что вы намеревались сравнивать вместо присваивания значение 40
.
С возвратным значением const
приведенный выше пример не будет компилироваться. Ну, по крайней мере, если компилятор не отбрасывает ключевое слово const
.