7

在我努力理解右值引用的过程中,我一直在思考编译器何时会确定特定的函数参数是右值引用,以及何时会确定它是左值引用。

(此问题与参考折叠有关;请参阅要求的参考折叠规则的简明解释:(1) A& & -> A& 、(2) A& && -> A& 、(3) A&& & -> A& 和 (4) A&& && -> A&& )。

特别是,我一直在考虑编译器是否总是将未命名的对象视为右值引用和/或编译器是否总是将临时对象视为右值引用。

反过来,这让我质疑未命名对象是否等同于临时对象。

我的问题是:未命名的对象总是临时的吗?临时对象总是未命名吗?

换句话说:未命名对象和临时对象是否等效

4

3 回答 3

3

可以命名临时对象。

非常常见的情况 - 作为参数传递给函数时。另一种不太常见的情况 - 将 const 引用绑定到函数的右值结果。

int f(int i) { return i + 1; }
int g() { const int &j = f(1); return j; }

未命名的对象通常是临时的,但并非总是如此。例如 - 匿名联合对象:

struct S
{
   union { int x; char y; };
} s;

当然,任何由operator new.

也许还有其他情况,但即使只有这些也可以作为假设的反例:)

于 2012-12-05T18:40:17.410 回答
3

I might be wrong, since I'm not sure what the definition of "unnamed object" is. But consider the argument of the foo() function below:

void foo(int)
{ /* ... */ }

int main()
{ foo(5); }

foo()'s argument is unnamed, but it's not a temporary. Therefore, unnamed objects and temporary objects are not equivalent.

于 2012-12-05T18:31:27.500 回答
2

我一直在思考什么时候编译器会确定一个特定的函数参数是一个右值引用,什么时候它会确定它是一个左值引用。

我假设您正在谈论具有通用参考参数的函数模板,像这样?

template<typename T>
void foo(T&& t)
{
}

规则非常简单。如果参数是类型的右值X,那么T将被推断为是X,因此T&&意味着X&&。如果参数是类型的左值X,那么将推T导出为X&,因此T&&意味着X& &&,它被折叠成X&

如果你真的在问arguments,那么这个问题没有多大意义,因为 arguments 从来都不是左值引用或右值引用,因为 type 的表达式X&会立即转换为 type 的表达式X,它表示引用的对象。

但是,如果您实际上的意思是“编译器如何区分左值参数和右值参数?” (注意缺少的参考),那么答案很简单:编译器知道每个表达式的值类别,因为标准为每个可能的表达式指定了它的值类别是什么。例如,函数的调用是可以属于以下三个值类别之一的表达式:

X   foo();   // the expression foo() is a prvalue
X&  bar();   // the expression bar() is an lvalue
X&& baz();   // the expression baz() is an xvalue

(当然,前提是它X本身不是引用类型。)

如果这些都不能回答您的问题,请澄清问题。此外,有些相关的常见问题解答

于 2012-12-05T19:00:16.333 回答