Yol*_*ola 207 c++ types reference conditional-operator lvalue
为什么第一个返回引用?
int x = 1;
int y = 2;
(x > y ? x : y) = 100;
Run Code Online (Sandbox Code Playgroud)
而第二个不?
int x = 1;
long y = 2;
(x > y ? x : y) = 100;
Run Code Online (Sandbox Code Playgroud)
实际上,第二个根本没有编译 - "没有左边的赋值".
CB *_*ley 173
表达式没有返回类型,它们具有类型,并且 - 在最新的C++标准中已知 - 值类别.
条件表达式可以是左值或右值.这是它的价值类别.(这有点简化,C++11
我们有lvalues,xvalues和prvalues.)
在非常宽泛和简单的术语中,左值是指内存中的对象,而右值只是一个值,可能不一定附加到内存中的对象.
赋值表达式为对象赋值,因此赋值的对象必须是左值.
对于条件表达式(?:
)是一个左值(再次,在广泛的和简单的术语),所述第二和第三操作数必须是左值的相同类型的.这是因为条件表达式的类型和值类别是在编译时确定的,并且必须是适当的,无论条件是否为真.如果必须将其中一个操作数转换为不同的类型以匹配另一个操作数,则条件表达式不能是左值,因为此转换的结果不是左值.
ISO/IEC 14882:2011参考:
3.10 [basic.lval]左值和右值(关于值类别)
5.15 [expr.cond]条件运算符(条件表达式具有的类型和值类别的规则)
5.17 [expr.ass]赋值和复合赋值运算符(要求赋值的lhs必须是可修改的左值)
Xeo*_*Xeo 57
三元?:
表达式的类型是其第二和第三个参数的常见类型.如果两种类型相同,则返回引用.如果它们可以相互转换,则选择一个,另一个转换(在这种情况下提升).由于您无法将lvalue引用返回到临时(转换/提升的变量),因此其类型是值类型.
Fil*_*efp 19
它不能返回左值,因为它必须隐式地提升x
匹配类型的类型y
(因为两边的:
类型不同),并且必须创建一个临时值.
表达式5.17赋值和复合赋值运算符
5.17/3
如果第二个和第三个操作数具有不同的类型,并且具有(可能是cv-qualified)类类型,则尝试将每个操作数转换为另一个操作数的类型.确定类型T1的操作数表达式E1是否可以转换为匹配类型T2的操作数表达式E2的过程定义如下:
- 如果E2是左值:如果可以将E1隐式转换(第4节)到类型"引用到T2",则E1可以转换为匹配E2,但受转换引用必须直接绑定的约束(8.5.3)到E1.
- 如果E2是右值,或者上述转换无法完成:
- 如果E1和E2具有类类型,并且底层类类型相同或者一个是另一个类的基类:如果T2的类与类型相同,则可以转换为E1以匹配E2,或者基类,T1的等级和T2的cv资格是与cv资格相同的cv资格,或者更高的cv资格.如果应用转换,则将E1更改为类型T2的右值,该值仍然引用原始源类对象(或其相应的子对象).[ 注意:即没有复制.- 结束注释 ]通过从E1复制初始化T2类型的临时值并将该临时值用作转换后的操作数.
否则(即,如果
E1
或E2具有非类型类型,或者它们都具有类类型但基础类不是相同的或者是另一个的基类):如果E1可以是E1,则可以转换为匹配E2如果E2被转换为rvalue(或者它具有的类型,如果E2是rvalue),则隐式转换为表达式E2将具有的类型.使用该过程,确定是否可以转换第二操作数以匹配第三操作数,以及是否可以转换第三操作数以匹配第二操作数.如果两者都可以转换,或者一个可以转换,但转换不明确,则程序格式不正确.如果两者都不能被转换,则操作数保持不变并且如下所述执行进一步检查.如果只能进行一次转换,则将该转换应用于所选操作数,并使用转换后的操作数代替本节其余部分的原始操作数.
5.17/4
如果第二个和第三个操作数是左值并且具有相同的类型,则结果是该类型并且是左值,如果第二个或第三个操作数是位字段,或者两者都是位,则它是位字段领域.
5.17/5
否则,结果是右值.如果第二个和第三个操作数不具有相同的类型,并且具有(可能是cv限定的)类类型,则使用重载决策来确定要应用于操作数的转换(如果有)(13.3.1.2,13.6) .如果重载决策失败,则程序格式错误.否则,应用如此确定的转换,并使用转换的操作数代替本节其余部分的原始操作数.