14

左值是绑定到内存的确定区域的值,而右值是一个表达式值,其存在是暂时的,不一定指向内存的确定区域。每当在需要右值的位置使用左值时,编译器都会执行左值到右值的转换,然后继续求值。

http://www.eetimes.com/discussion/programming-pointers/4023341/Lvalues-and-Rvalues

每当我们构造一个临时(匿名)类对象或从函数返回一个临时类对象时,虽然该对象是临时的,但它是可寻址的。但是,该对象仍然是有效的右值。这意味着对象是 a) 可寻址右值或 b) 当编译器期望使用左值时,它正在从左值隐式转换为右值。

例如:

class A
{
public:
    int x;
    A(int a) { x = a; std::cout << "int conversion ctor\n"; }
    A(A&) { std::cout << "lvalue copy ctor\n"; }
    A(A&&) { std::cout << "rvalue copy ctor\n"; }
};
A ret_a(A a) 
{
    return a;
}

int main(void)
{
    &A(5); // A(5) is an addressable object
    A&& rvalue = A(5); // A(5) is also an rvalue
}

我们还知道,函数返回的临时对象(在以下情况下a)是左值,如下代码段:

int main(void)
{
    ret_a(A(5));
}

产生以下输出:

int conversion ctor

lvalue copy ctor

表示ret_a使用实参A(5)调用函数调用转换构造函数A::A(int),该构造函数构造函数的形式参数a,值为 5。

当函数完成执行时,它会构造一个临时A对象,使用a它作为参数,调用A::A(A&). 但是,如果我们A::A(A&)要从重载构造函数列表中删除,返回的临时对象仍然会匹配右值引用构造函数A::A(A&&)

这是我不太理解的:对象如何同时a匹配右值引用和左值引用?很明显,这A::A(A&)是比A::A(A&&)(因此a必须是左值)更好的匹配。但是,由于不能将右值引用初始化为左值,鉴于形式参数a是左值,它不应该能够匹配对A::A(A&&). 如果编译器正在进行左值到右值的转换,那将是微不足道的。A::A(A&)事实上,从 'A' 到 'A&' 的转换也是微不足道的,两个函数应该具有相同的隐式转换序列等级,因此,当两者A::A(A&&)都在重载函数中时,编译器不应该能够推断出最佳匹配函数候选集。

此外,问题(我之前问过的)是:

给定对象如何同时匹配右值引用和左值引用?

4

1 回答 1

6

为了我:

int main(void)
{
    ret_a(A(5));
}

产量:

int conversion ctor
rvalue copy ctor

(即右值,而不是左值)。这是您的编译器中的一个错误。然而,这是可以理解的,因为这种行为的规则仅在几个月前(2010 年 11 月)发生了变化。更多关于这下面。

当函数完成执行时,它会构造一个临时A 对象,使用a它作为参数,调用A::A(A&).

其实没有。当函数ret_a完成执行时,它会构造一个临时A对象,使用a它作为参数,调用A:A(A&&). 这是由于 [class.copy]/p33] 1

当满足或将满足复制操作的省略标准时,除了源对象是函数参数的事实,并且要复制的对象由左值指定时,选择复制的构造函数的重载决策是首先执行好像对象是由右值指定的。如果重载决议失败,或者如果所选构造函数的第一个参数的类型不是对对象类型的右值引用(可能是 cv 限定的),则再次执行重载决议,将对象视为左值。[注意:无论是否会发生复制省略,都必须执行此两阶段重载解析。如果不执行省略,它确定要调用的构造函数,即使省略了调用,所选的构造函数也必须是可访问的。——尾注]

但是,如果您删除A::A(A&&)构造函数,A::A(&)则将选择返回。尽管在这种情况下,参数的构造a将失败,因为您不能使用右值构造它。但是暂时忽略这一点,我相信您的最终问题是:

给定对象如何同时匹配右值引用和左值引用?

在提及该声明时:

return a;

答案在上面引用的标准草案段落中:尝试第一次重载解析,就好像a是一个右值。如果失败,则使用a左值再次尝试重载解析。这个两阶段过程仅在允许复制省略的上下文中尝试(例如返回语句)。

C++0x 草案最近刚刚更改为在返回按值传递的参数时允许两阶段重载解析过程(如您的示例中所示)。这就是我们看到的不同编译器行为不同的原因。

于 2011-03-11T00:36:32.660 回答