Я начну с вашего последнего вопроса
Кроме того, почему компилятор или 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
y = 5
это выражение, и оно имеет значение5
. Почему вы думаете, что нет?