Я начну с вашего последнего вопроса
Кроме того, почему компилятор или 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