C++ 从r值ref到l值ref的转换,为什么有效?

C++ 从r值ref到l值ref的转换,为什么有效?,c++,c++11,C++,C++11,在我看来,将一个r值引用转换为一个l值引用并最终将一个临时值作为一个l值访问是没有意义的。例如: struct S { int val=5; }; void foo(S &&s) { S &s2=s; s2.val=7 } void foo2(S &s2) { s2.val=7 } int main() { foo(S()); // This is fine foo2(S()); // Error: Even though thi

在我看来,将一个r值引用转换为一个l值引用并最终将一个临时值作为一个l值访问是没有意义的。例如:

struct S
{
  int val=5;
};

void foo(S &&s)
{
  S &s2=s;

  s2.val=7
}

void foo2(S &s2)
{
  s2.val=7
}

int main()
{
  foo(S());  // This is fine
  foo2(S()); // Error: Even though this is logically equivalent to foo()
}

<> >调用<代码>()/<代码>似乎在C++中是有效的,或者至少它与GCC 4.7.1编译。对
foo2()
的调用并非如此,尽管这两个函数在逻辑上似乎是等价的。给出什么?

s
与任何其他命名变量一样,已经是左值。因此,对它进行左值引用并不会真正改变任何事情

右值和左值在概念上的关键区别在于,只能访问右值一次,这使得对右值执行奇怪的操作是安全的。但是如果一次访问将它绑定到一个右值引用,那么您只是创建了一种多次访问它的方法,即将它转换为左值。因此,您不能隐式地将它绑定到另一个右值引用,而可以将它绑定到左值引用

编辑:

这两件事在逻辑上并不等同。在一种方法中,将右值绑定到左值引用。这是不允许的,因为这是误导。(没有允许左值绑定到右值引用那么危险,但仍然具有误导性。)
foo2
通过接受左值引用,宣布它可能会修改传递的对象,这绝对是函数操作的核心部分。向这样的函数传递一个临时变量是没有意义的,因为您无法观察修改

在另一种情况下,将右值绑定到右值引用
foo
,通过采用右值引用,宣布它可能会修改传递的对象,但这是一种性能优化,外部任何人都无法观察到。传递一个临时变量是有意义的,但是传递一个非临时变量是非常危险的,这就是为什么在这种情况下必须显式地
std::move
参数的原因

然后,在
foo
中,将左值(碰巧是一个引用右值引用类型变量的表达式,但这并不相关)绑定到左值表达式。这是有意义的:您已经得到了您的右值引用变量
s
,它指向一些东西,由于已经传递给您的函数,这些东西已经成为您的玩物。因此,如果您想将其传递给修改其状态的对象(例如
foo2
),然后观察这些更改(您可以通过
s
s2
两者),这在概念上是完全正确的


基本上,只需观察一次或多次就可以了,这是一个范围问题。这就是为什么“同一”事物(其实不是同一事物,但你这么认为)可以在一个上下文中绑定到右值引用,在另一个上下文中绑定到左值引用。

s
与任何其他命名变量一样,已经是左值了。因此,对它进行左值引用并不会真正改变任何事情

右值和左值在概念上的关键区别在于,只能访问右值一次,这使得对右值执行奇怪的操作是安全的。但是如果一次访问将它绑定到一个右值引用,那么您只是创建了一种多次访问它的方法,即将它转换为左值。因此,您不能隐式地将它绑定到另一个右值引用,而可以将它绑定到左值引用

编辑:

这两件事在逻辑上并不等同。在一种方法中,将右值绑定到左值引用。这是不允许的,因为这是误导。(没有允许左值绑定到右值引用那么危险,但仍然具有误导性。)
foo2
通过接受左值引用,宣布它可能会修改传递的对象,这绝对是函数操作的核心部分。向这样的函数传递一个临时变量是没有意义的,因为您无法观察修改

在另一种情况下,将右值绑定到右值引用
foo
,通过采用右值引用,宣布它可能会修改传递的对象,但这是一种性能优化,外部任何人都无法观察到。传递一个临时变量是有意义的,但是传递一个非临时变量是非常危险的,这就是为什么在这种情况下必须显式地
std::move
参数的原因

然后,在
foo
中,将左值(碰巧是一个引用右值引用类型变量的表达式,但这并不相关)绑定到左值表达式。这是有意义的:您已经得到了您的右值引用变量
s
,它指向一些东西,由于已经传递给您的函数,这些东西已经成为您的玩物。因此,如果您想将其传递给修改其状态的对象(例如
foo2
),然后观察这些更改(您可以通过
s
s2
两者),这在概念上是完全正确的


基本上,只需观察一次或多次就可以了,这是一个范围问题。这就是为什么“同一”事物(其实不是同一事物,但你这么认为)可以在一个上下文中绑定到右值引用,而在另一个上下文中绑定到左值引用。

你没有转换任何东西。您正在将表达式
s
的值绑定到引用变量
s2
。这没什么问题。您可以直接在
foo()内执行
s.val=7
。所以
&
&
之间没有真正的区别,它们可以以相同的方式使用。事实上,(设计上)很难区分它们之间的区别。最重要的区别是,当
&&
是函数参数类型的一部分时,它允许它绑定(作为引用)到临时变量