Почему int x {y = 5} возможно? - PullRequest
10 голосов
/ 18 октября 2019
int main() {
    int y;
    int x{ y = 5 };
    //x is 5
}

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

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

Ответы [ 4 ]

16 голосов
/ 18 октября 2019

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

Это присваивание, и присваивания дают значения, т. Е. Тип "cv-unqualified" слеваоперанд ", см. [expr.ass / 3] . Следовательно, y = 5 приводит к y, то есть 5, который используется для инициализации x.

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

В теле основной функции нет необходимости содержать оператор return: если управление достигает конца основногобез обращения к оператору return эффект заключается в выполнении return 0;.

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

10 голосов
/ 18 октября 2019

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

Кроме того, почему компилятор или 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
4 голосов
/ 18 октября 2019

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

int x, y, z;
x = y = z = 1;
3 голосов
/ 18 октября 2019

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...