Почему int x {y = 5} возможно?

10
int main() {
    int y;
    int x{ y = 5 };
    //x is 5
}

Как это возможно, поскольку y = 5 не является вычисляемым выражением?

Кроме того, почему компилятор или IDE не жалуются на то, что main () не возвращает int?

counterstriker0
источник
8
y = 5 это выражение, и оно имеет значение 5. Почему вы думаете, что нет?
бесполезно
2
Что касается пропавших без вести returnв mainсм этот вопрос .
орех
3
А еще лучше, удалите второй вопрос. Один одиночный вопрос на вопрос является предпочтительной моделью на переполнение стека.
StoryTeller - Unslander Monica
Возможно, вам следует переопределить вопрос, почему y = 5здесь получается 5. Возможность операторов присваивания возвращать что-то действительно странная особенность C / C ++.
user7860670

Ответы:

11

Я начну с вашего последнего вопроса

Кроме того, почему компилятор или IDE не жалуются на то, что main () не возвращает int?

Согласно стандарту C ++ (основная функция 6.6.1)

5 Оператор return в main приводит к выходу из функции main (уничтожению любых объектов с автоматическим хранением) и вызову std :: exit с возвращаемым значением в качестве аргумента. Если управление выходит за пределы составного оператора main, эффект эквивалентен возврату с операндом 0 (см. Также 18.3).

И относительно этого вопроса

Как это возможно, поскольку y = 5 не является вычисляемым выражением?

Из стандарта C ++ (8.18 Операторы присваивания и составного присваивания)

1 Оператор присваивания (=) и составные операторы присваивания все группы справа налево. Все они требуют изменяемого lvalue в качестве своего левого операнда и возвращают lvalue, ссылаясь на левый операнд.

Sp это объявление

int x{ y = 5 };

может быть эквивалентно разделен на два утверждения

y = 5;
int x{ y };

Более того, в C ++ вы можете даже сделать ссылку на переменную y следующим образом

int &x{ y = 5 };

Вот демонстрационная программа

#include <iostream>

int main() 
{
    int y;
    int &x{ y = 5 };    

    std::cout << "y = " << y << '\n';

    x = 10;

    std::cout << "y = " << y << '\n';
}

Его вывод

y = 5
y = 10

Вы можете эту декларацию

int x{ y = 5 };

переписать тоже как

int x = { y = 5 };

Однако примите во внимание, что между этими двумя объявлениями (похожими на вышеприведенные объявления) есть разница.

auto x{ y = 5 };

а также

auto x = { y = 5 };

В первом объявлении переменная xимеет тип int. Во втором объявлении переменная xимеет тип std::initializer_list<int>.

Чтобы сделать разницу более заметной, посмотрите, как выводятся значения объектов.

#include <iostream>

int main() 
{
    int y;
    auto x1 { y = 5 };  

    std::cout << "x1 = " << x1 << '\n';

    auto x2 = { y = 10 };   

    std::cout << "*x2.begin()= " << *x2.begin() << '\n';

    std::cout << "y = " << y << '\n';

    return 0;
}

Выход программы

x1 = 5
*x2.begin()= 10
y = 10
Влад из Москвы
источник
16

Как это возможно, поскольку y = 5 не является вычисляемым выражением?

Это присваивание, и присваивания дают значения, то есть «cv-неквалифицированный тип левого операнда», см. [Expr.ass / 3] . Следовательно y = 5приводит y, который 5, который используется для инициализации x.

Относительно вашего второго вопроса смотрите cppreference на main (или [basic.start.main / 5] ):

Тело функции main не обязательно должно содержать returnоператор: если управление достигает конца main, не встречая returnоператора, эффект - выполнение return 0;.

Следовательно, компилятор или IDE, предупреждающие вас о пропущенном returnоператоре в конце main, будут просто ошибочными. По общему признанию, тот факт, что вы всегда должны returnобъекты из не- voidфункции execpt,main является своего рода ... ну, по историческим причинам, я думаю.

lubgr
источник
2
Выражение может привести к значению, но может сделать только функция return. -педантика
бесполезная
Я думаю, что это int x {y = 5}; утверждение недействительно в c
bhura
@bhura - вопрос о С ++, а не о С
StoryTeller - Unslander Monica
Возможно, стоит упомянуть, что, даже если это не требуется, возвращение значения из main обычно считается хорошей практикой?
Аконкагуа
4

В operator=()приводит к значению, которое является значение , присвоенное переменной. Из-за этого возможно связать назначения так:

int x, y, z;
x = y = z = 1;
RHertel
источник
Выражение присваивания имеет значение . Функции имеют возвращаемые значения; выражений нет.
Пит Беккер
3

Если вы посмотрите на документацию по cppreference , то увидите, что она operator=()возвращает ссылку на назначенный объект. Следовательно, назначение может использоваться как выражение, которое возвращает объект, который был назначен.

Тогда это просто нормальное задание с фигурными скобками.

Xatyrian
источник