未命名对象和临时对象是否等价?

7
在理解右值引用的过程中,我一直在考虑编译器何时会确定特定函数参数是右值引用,何时会确定其为左值引用。这个问题与引用折叠有关,请参见引用折叠规则的简明解释:(1)A& & -> A&,(2)A& && -> A&,(3)A&& & -> A&,以及(4)A&& && -> A&&
特别地,我一直在考虑编译器是否总是将未命名对象视为右值引用,或者是否总是将临时对象视为右值引用。
因此,我开始质疑未命名对象是否等同于临时对象。
我的问题是:未命名对象总是临时的吗?临时对象总是未命名的吗?
换句话说:未命名对象和临时对象是否等效

我不太熟悉技术术语,无法用作答案发布,但我认为这是一个反例:“void foo(int) {}”。在这里,参数是一个没有名称的非临时对象。 - GManNickG
好点子。这个例子似乎清楚地表明,与匿名变量相比,临时对象更相关于右值引用。 - Dan Nissenbaum
“未命名对象”是否有实际定义? - Nikos C.
1
我想了解“临时对象”的定义(以及...)。 - Dan Nissenbaum
3个回答

3

我可能是错误的,因为我不确定“未命名对象”的定义是什么。但请考虑下面foo()函数的参数:

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

int main()
{ foo(5); }

foo()的参数没有名称,但它不是一个临时对象。因此,无名对象和临时对象并不相等。


3

临时对象可以被命名。

非常常见的情况是将其作为参数传递给函数。另一个不太常见的情况是将const引用绑定到函数返回的rvalue结果上。

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创建的对象也是如此。

也许还有其他情况,但即使只有这些,也足以证明这个假设是不成立的 :)


2
我一直在思考编译器何时会确定一个特定的函数参数为右值引用,以及何时会将其确定为左值引用。您是不是在谈论像这样具有通用引用参数的函数模板?
template<typename T>
void foo(T&& t)
{
}

规则非常简单。如果参数是类型为X的rvalue,则T将被推断为X,因此T&&表示X&&。如果参数是类型为X的lvalue,则T将被推断为X&,因此T&&表示X& &&,它被折叠成X&
如果您真正问的是参数,那么这个问题并没有太多意义,因为参数永远不会是lvalue引用或rvalue引用,因为类型为X&的表达式立即转换为类型为X的表达式,表示引用的对象。
但是,如果您实际上是想问“编译器如何区分lvalue参数和rvalue参数?”(请注意缺少引用),那么答案很简单:编译器知道每个表达式的值类别,因为标准针对每个可能的表达式规定了其值类别。例如,函数调用是一个可以属于三种值类别之一的表达式:
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本身不是引用类型。)
如果这些都没有回答你的问题,请澄清一下问题。此外,有些相关的常见问题解答

快速跟进:假设您有int x; int & y = x;,那么y的类型是什么 - int还是int& - Dan Nissenbaum
答案取决于你正在交谈的人和你当前要考虑的语言特性 :) 例如,decltype(y)decltype((y)) 都是 int&,但我认为 decltype 是唯一一个被认为类型是引用的情况。如果我错了,请纠正我! 标准说:“如果表达式最初具有“对 T 的引用”(8.3.2、8.5.3),则在进一步分析之前将类型调整为 T。表达式指定由引用所表示的对象或函数,并且该表达式是 lvalue 或 xvalue,具体取决于表达式。” - fredoverflow
auto&&T&& 也可以推断类型作为引用。 - Puppy
1
关于我之前的评论:即,给定 class A; void foo(A&& a_); int main() { foo(A()); } - 参数 类型是 右值引用,对应于 A()参数类型右值,而对应于 a_参数类型 是(有趣的)左值,正确吗? - Dan Nissenbaum
1
你必须小心不要混淆类型和值类别。参数typeA&&(对A的右值引用),而参数value category是lvalue。所有参数都是lvalues,无论它们的类型如何,因为所有参数都有名称,而大多数名称都是lvalues。参数typeA,参数value category是prvalue。 - fredoverflow
1
跟进一下...我非常强烈推荐@FredOverflow的链接文章(在他的回答底部);它非常出色,尽管他评论说它“有些相关”,但他可能是因为自己写了链接中的文章所以保持低调,实际上它详细地涵盖了整个主题。 - Dan Nissenbaum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接