C ++03§4.2N°1:
类型为“NT的数组”或“T的未知边界数组”的左值或右值可以转换为“指向T的指针”的右值。结果是指向数组的第一个元素的指针。
长期以来,这句话让我感到困惑的是,我不太明白数组类型的右值是什么意思。也就是说,我无法想出一个表达式,其类型是一个数组,结果是一个右值。我读了this线程,基本上问了同样的问题,接受的答案是“不,没有数组类型的右值”。我想我可能与此有矛盾。
C ++03§5.2.5N°4: (关于表达式E1.E2)
如果E2是非静态数据成员,并且E1的类型是“cq1 vq1 X”,并且E2的类型是“cq2 vq2 T”,则表达式指定由第一个指定的对象的指定成员表达。如果E1是左值,则E1.E2是左值。
我认为否则它是一个右值(假设E2不是参考,那个案例由§5.2.5 N°3
覆盖)因此......
struct A
{
int a[4];
};
A f()
{
A a;
return a;
}
int main()
{
f().a; //I think this is an rvalue of array type...
}
我在这里看到两个选项:
选项1: 我是正确的,欢呼,喜欢,很酷。在这种情况下,问题是:还有其他例子吗?
选项2: 我不对,在这种情况下问题是:这是标准的缺陷吗?
我不知道1,但我真的怀疑2,因为当他们谈到函数到指针的转换时,他们只提到了函数类型的左值(很明显没有这样的rvalues)。所以他们很可能已经考虑了数组类型的rvalues。
所以,基本上我的问题是我是否提出了数组类型右值的例子,如果没有,请提供一个有效的例子,我坚信它存在。
答案 0 :(得分:11)
是的,你是对的。表达式是数组类型的右值。这不是缺陷 - 委员会知道它,它也是C89中的一个常见问题,它只允许转换为数组类型左值的指针。因此,您无法对f().a
之类的数组进行索引或取消引用。 C99解决了这个问题,而C ++没有问题。
注意,它是否是rvalue与表达式是否表示对象无关。 C ++ 03意外省略,表示数组类型的右值表达式表示一个对象。这是在C ++ 0x by DR#450中修复的。
(显然很欣赏没有这样的rvalues)
实际上有函数类型的rvalues。对于由类成员访问表达式
表示的非静态成员函数,会出现这些情况struct A { void f(); };
/* A().f is an rvalue of type "void()" */
int main() { A().f(); }
答案 1 :(得分:-3)
A是右值。里面的数组不是。想象一下,在该临时对象上有一个方法链的情况 - 其中的变量存在多个方法调用和返回,并且它们可以将引用(在链的持续时间内有效)传递给其他函数。这些功能事先无法知道它们应被称为右值。
在最新版本的草稿中,您可以在rvalue / lvalue *上重载函数。然而,即使这样,一个右值引用也不会产生所谓rvalue的内容,而且我不完全确定任何编译器目前支持这个,我知道MSVC没有。
事实上,使用decltype,您可以轻松确定编译器将该数组称为左值。
考虑:
template<typename A, typename B> auto sum(A&& a, B&& b) -> decltype(std::forward<A>(a) + std::forward<B>(b)) {
return std::forward<A>(a) + std::forward<B>(b);
}
这就是decltype的用途,它绝对区分了左值和右值。或者,考虑一下:
int main()
{
auto var = f().a;
}
Var是一个int *。这是一个瞬间失败,因为f()。a立即死亡。不确定我对此的直接看法,但它肯定不适用于右值。