见下面的例子:
int arr[10];
int *p = arr; // 1st valid choice
int (&r)[10] = arr; // 2nd valid choice
现在,当我们对auto
使用arr
时,它会选择第一个选项。
auto x = arr; // x is equivalent to *p
答案 0 :(得分:24)
是。在该表达式中,由于lvalue-to-rvalue
转换,数组衰减为指针类型。
如果您想要数组类型,而不是指针类型,请执行以下操作:
auto & x = arr; //now it doesn't decay into pointer type!
目标类型中的 &
可防止数组衰减为指针类型!
x
是一个数组而不是指针,可以证明为:
void f(int (&a)[10])
{
std::cout << "f() is called. that means, x is an array!" << std::endl;
}
int main() {
int arr[10];
auto & x = arr;
f(x); //okay iff x is an int array of size 10, else compilation error!
}
输出:
f() is called. that means, x is an array!
在ideone演示:http://www.ideone.com/L2Ifp
请注意,指针类型无法调用f
。可以使用大小为int
的{{1}}数组调用它。尝试使用任何其他类型调用它将导致编译错误。
答案 1 :(得分:5)
为行为提供标准参考,7.1.6.4 [dcl.spec.auto]第6段内容如下:
一旦根据8.3确定了declarator-id的类型,使用declarator-id的声明变量的类型是使用模板参数推断规则从其初始化程序的类型确定的。令T为已为变量标识符d确定的类型。通过用一个新发明的类型模板参数U替换auto的出现来从T获得P ...对于变量d推导出的类型然后是使用函数调用中的模板参数推导规则确定的推导A(14.8) .2.1),其中P是函数模板参数类型,d的初始值设定项是相应的参数。如果扣除失败,则声明格式不正确。
所以我们需要寻找其他地方,特别是14.8.2.1 [tmp.deduct.call]第2段:
如果P不是引用类型: - 如果A是数组类型,则使用数组到指针标准转换(4.2)生成的指针类型代替A进行类型推导
为了完整起见,4.2 [conv.array]第1段:
“N T数组”或“未知T的数组”类型的左值或右值可以转换为“指向T的指针”类型的prvalue。结果是指向数组的第一个元素的指针。
要逐步执行此操作,auto x = arr;
会创建一个虚构的函数template<typename P> f(P);
,并尝试从调用P
中推断出f(arr)
。在这种情况下,A
为array of 10 int
,而P
不是引用类型,因此A
会变为pointer to int
。其中将链条渗透回最终类型的x
。
所以基本上,它被视为指针,因为规则说它必须。这种行为更加有用,因为数组不可分配。否则,你的auto x = arr;
将无法编译而不是做一些有用的事情。
答案 2 :(得分:4)
auto
产生价值。它不会产生参考。考虑到这一点,那么指针就是对数组提供的值的简单转换。
答案 3 :(得分:0)
对于数组arr
,表达式arr
本身意味着&arr[0]
。此规则来自C.因此,IMO,auto选择指针。