Подтвердить что ты не робот

Предупреждение 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?

4b9b3361

Ответ 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.