我有一些使用auto
的案例:
auto s = expr; //s is always lvalue
auto & s = expr; //s is always lvalue reference? What if expr is rvalue?
auto && s = expr; //s is perfectly forwarded
他们是真的吗?如果没有,为什么?
答案 0 :(得分:5)
dyp是正确的,我想详细说明。
首先,结论是来自dyp:
定义了变量声明中
auto
推导出的类型 通过模板参数推导的规则,见[dcl.spec.auto] / 6; 有一个例外:如果初始化程序是braced-init-list,那么 推导出的类型是std::initializer_list
。
我会解释。
首先,
auto s = expr;
这与从T
推断expr
,
template<class T>
void f(T s);
f(expr);
模板参数推导的规则非常复杂,因为你只关注左值和右值的东西,让我们关注它。
模板参数推导是通过比较模板参数类型(称之为P
,在本例中为P
是T
)和相应的参数(称之为A
在这种情况下,expr
)的类型。
从14.8.2.1起,
如果P不是参考类型:
- 如果A是数组类型,则数组到指针标准转换(4.2)产生的指针类型是 代替A代替类型扣除;否则,
- 如果A是函数类型,则函数到指针标准转换产生的指针类型(4.3) 用于代替A进行类型扣除;否则,
- 如果A是cv限定类型,则类型扣除将忽略A类型的顶级cv限定符。
因此,如果expr
是数组或函数,它将被视为指针,如果expr具有cv-qualification(const
等),它们将被忽略。
如果
P
是cv限定类型,则类型扣除将忽略P
类型的顶级cv限定符。
这实际上说:
const auto s = expr;
s
是一个const
变量,但对于auto
目的的类型扣除,const
将被删除。
因此,根据上述规则,auto
将推断为expr
的类型(在上述某种类型转换后)。
请注意,当表达式是T
的引用时,在先前分析之前,它将调整为T
。
无论expr
是什么 - rvalue,lvalue或lvalue / rvalue ref类型 - auto
的类型始终是expr
的类型,没有引用。
auto s1 = 1; //int
int &x = s1;
auto s2 = x; //int
int &&y = 2;
auto s3 = y; //int
其次,让我们来看看
auto &s = expr;
这与
相同template<class T>
void f(T &s);
f(expr);
标准的额外规则如下:
如果
P
是引用类型,P
引用的类型将用于类型扣除。
因此,自动扣除与没有&
完全相同,但扣除auto
类型后,&
会添加到auto
的末尾。
//auto &s1 = 1; //auto is deducted to int, int &s1 = 1, error!
const auto &s1 = 1; //auto is deducted to int, const int &s1 = 1; ok!
const int &x = s1;
auto &s2 = x; //auto is int, int &s2 = x; ok!
int &&y = 2;
auto &s3 = y; //auto is int, int &s3 = y; ok!
请注意,最后一个y
是左值。 C ++的规则是:命名的右值引用是一个左值。
最后:
auto &&s = expr;
这无疑与
相同template<class T>
void f(T &&s);
f(expr);
标准的另一条规则:
如果
P
是对cv-nonqualified模板参数的右值引用 参数是左值,使用类型“左值引用A”A
的地方类型扣除。
实际上,如果expr
是右值,则规则与第二种情况(左值案例)相同,但如果expr
是左值,则{{1}的类型}将是A
的左值引用。
从前面的解释中注意,A
永远不会引用,因为表达式的类型永远不是引用。但是对于这种特殊情况(A
,而auto &&
是左值),必须使用A
的引用,无论A
本身是否为引用类型。
示例:
expr
答案 1 :(得分:0)
由于没有人给出答案,我现在明白了(感谢@dyp),我只想自己发表答案。指出错误,如果有的话:
auto s = expr;
如果expr
是左值,右值或任何引用,s
始终是左值并且复制。
auto& s = expr;
如果expr
是左值,左值参考或左值参考,s
是左值参考。
如果expr
是prvalue,则表示错误且不合法。
auto&& s = expr;
完全转发 s
(rvalue将成为右值参考并崩溃)。