自动推导类型是怎样的

How does auto deduce type?

本文关键字:类型      更新时间:2023-10-16

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

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

dyp是正确的,我想详细说明。

首先,结论来自dyp:

定义了在变量声明中为auto推导的类型通过模板参数推导规则,请参见[dcl.spec.auto]/6;有一个例外:如果初始值设定项是一个有支撑的init列表,则推导出的类型是CCD_ 3。

我来解释。

首先,

auto s = expr;

这与从expr、推导T相同

template<class T>
void f(T s);
f(expr);

模板参数推导的规则非常复杂,因为你只关心左值和右值的东西,让我们专注于此。

模板参数推导是通过比较模板参数类型(称为P,在本例中PT)和相应的参数(称为A,在本案中为expr的类型)。

从14.8.1.1开始,

如果p不是参考类型:

--如果A是数组类型,则数组到指针标准转换(4.2)产生的指针类型为用于代替A进行类型推导;否则,

--如果A是函数类型,则函数到指针标准转换(4.3)产生的指针类型用于代替A进行类型推导;否则,

--如果A是cv限定类型,则在类型推导时忽略A类型的顶级cv限定符。

因此,如果expr是数组或函数,它将被视为指针,如果expr具有cv限定(const等),它们将被忽略。

如果P是cv限定类型,则忽略P的类型的顶级cv限定符进行类型推导。

这实际上是说:

const auto s = expr;

sconst变量,但对于auto的类型推导,const将被删除。

因此,根据上述规则,auto将被推导为expr的类型(在上述的某种类型转换之后)。

注意,当表达式是对T的引用时,在先前分析之前,它将被调整为T

因此,无论expr是什么——右值、左值或左值/右值引用类型——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类型后,std::initializer_list0将添加到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不合格模板参数的右值引用,并且参数是左值,类型"对A的左值引用"用于代替A进行类型推导。

这实际上表明,如果expr是右值,则规则将与第二种情况(左值情况)相同,但如果expr是左值,则A的类型将是对A的左值引用。

请注意,根据前面的解释,A永远不是引用,因为表达式的类型永远不是引用。但对于这种特殊情况(auto &&A是左值),必须使用对A的引用,而不管expr本身是否是引用类型。

示例:

auto &&s1 = 1; //auto is deducted to int, int &&s1 = 1, ok!
int x = 1;
auto &&s2 = x; //x is lvalue, so A is int &, auto is deducted to int &, int & &&s2 = x; ok!
int &&y = 2;
auto &&s3 = y; //y is lvalue, auto is int &, int & &&s3 = y; ok!

由于没有人给出答案,而且我现在有点理解了(多亏了@dyp),我只会自己发布答案。指出错误(如果有):

auto s = expr;

如果expr是左值、prvalue或任何引用,则s始终是左值,并进行复制。

auto& s = expr;

如果expr是左值、左值引用或右值引用,则s是左值引用。如果expr是prvalue,则这是一个错误,不合法。

auto&& s = expr;

CCD_ 49被完美地转发(右值将变成右值参考和塌陷)。