为什么 int x{ y = 5 } 是可能的?

Why is int x{ y = 5 } possible?

提问人:discape 提问时间:10/18/2019 最后编辑:Vlad from Moscowdiscape 更新时间:10/18/2019 访问量:658

问:

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

这怎么可能,因为 y = 5 不是可计算的表达式?

另外,为什么编译器或 IDE 不抱怨 main() 不返回 int?

C++ 初始化 声明 值运算符

评论

8赞 Useless 10/18/2019
y = 5 是一个表达式,它有价值。你为什么不认为呢?5
2赞 walnut 10/18/2019
关于缺失的问题,请参阅此问题returnmain
3赞 StoryTeller - Unslander Monica 10/18/2019
更好的是,删除第二个问题。每个问题一个问题是 Stack Overflow 上的首选模型。
0赞 user7860670 10/18/2019
也许你应该在这里重新定义为什么产生 5 的问题。赋值运算符返回某些内容的可能性确实是 C/C++ 的一个奇怪功能。y = 5

答:

16赞 lubgr 10/18/2019 #1

这怎么可能,因为 y = 5 不是可计算的表达式?

它是一个赋值,赋值产生值,即“左操作数的 cv-unqualified 类型”,参见 [expr.ass/3]。因此得到 ,即 ,用于初始化 。y = 5y5x

关于第二个问题,请参阅 main 上的 cpreference(或 [basic.start.main/5]):

main 函数的主体不需要包含语句:如果 control 到达 main 的末尾而没有遇到语句,则效果是执行 .returnreturnreturn 0;

因此,编译器或 IDE 警告您在末尾缺少语句是完全错误的。诚然,您应该始终从非函数 execpt main 中获取对象这一事实有点......好吧,我猜是出于历史原因。returnmainreturnvoid

评论

2赞 Useless 10/18/2019
表达式可以产生一个值,但只有函数可以产生一个值。-迂return
0赞 Malik Ji 10/18/2019
我认为这个 int x{y=5};语句在 C 中无效
0赞 StoryTeller - Unslander Monica 10/18/2019
@bhura - 问题是关于C++,而不是 C
0赞 Aconcagua 10/19/2019
也许值得一提的是,即使不是必需的,仍然从 main 返回值通常被认为是好的做法?
3赞 Xatyrian 10/18/2019 #2

如果您查看有关 cpppreference 的文档,您会看到返回对已分配对象的引用。因此,赋值可以用作返回已赋值对象的表达式。operator=()

然后,这只是一个带有大括号的正常作业。

4赞 RHertel 10/18/2019 #3

结果生成一个值,该值是分配给变量的值。因此,可以像这样链接分配:operator=()

int x, y, z;
x = y = z = 1;

评论

0赞 Pete Becker 10/18/2019
赋值表达式具有一个值。函数具有返回值;表达式则不然。
11赞 Vlad from Moscow 10/18/2019 #4

我将从你的最后一个问题开始

另外,为什么编译器或 IDE 不抱怨 main() 没有 返回 int?

根据 C++ 标准(6.6.1 主功能)

5 main 中的 return 语句具有离开 main 的效果 函数(销毁任何具有自动存储持续时间的对象)和 使用返回值作为参数调用 std::exit。如果控制 流出 main 的复合语句的末尾,效果是 等同于操作数为 0 的返回(另见 18.3)。

而相对于这个问题

这怎么可能,因为 y = 5 不是可计算的表达式?

来自 C++ 标准(8.18 赋值和复合赋值运算符)

1 赋值运算符 (=) 和复合赋值运算符 所有组从右到左。所有这些都需要一个可修改的左值作为它们的左 操作数并返回一个左操作数的左值。

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 };

在第一个声明中,变量的类型为 。 在第二个声明中,变量的类型为 。xintxstd::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