如何自动推断类型?

时间:2014-01-12 01:03:16

标签: c++ c++11

我有一些使用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

他们是真的吗?如果没有,为什么?

2 个答案:

答案 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,在本例中为PT)和相应的参数(称之为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将成为右值参考并崩溃)。