我想我可能想出了一个rvalue数组类型的例子

时间:2010-10-30 10:00:17

标签: c++ arrays rvalue lvalue-to-rvalue

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。

所以,基本上我的问题是我是否提出了数组类型右值的例子,如果没有,请提供一个有效的例子,我坚信它存在。

2 个答案:

答案 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立即死亡。不确定我对此的直接看法,但它肯定不适用于右值。