对 'auto' 扣除类型的困惑

Confusion about 'auto' deduction type

int i = 0;

相当于

int i;
i = 0;

然后,

auto i = 0;

没关系,工作正常。但是,

auto i;
i = 0;

编译报错。

那么,为什么编译器会报错?

代码

auto i;
i = 0;

甚至不应该编译,因为在编译时无法确定 i 的类型,因为没有像您前面的示例那样直接赋值,因此编译器不知道用什么替换 auto 代替 i 与。在你的第一个例子中,你有 auto i = 0;,直接赋值告诉编译器 i 应该是 integer 类型。

文档

自动类型需要由编译器推导出来,并且一旦类型设置就无法更改。这是一个编译时操作。因此需要初始化。这实际上就是它的重点,通过将所有内容移动到 =

的右侧来确保变量初始化

auto 只是意味着编译器将推断类型。你不给它任何信息,直到那一行,它可以用来决定所需的类型和大小。

auto i;
i = 0;

将无法工作,因为 auto 从其 初始化器 推导出 i 的类型,在这种情况下,您 没有初始化器.

另一方面,这有效:

auto i = 0;

因为现在你确实有一个初始值设定项 - 0 - 因为文字 0 的类型是 int 这就是 auto 推导出 i 的类型为。

不等价,因为 auto 不是类型。在这两个示例中,i 类型都是 intauto 意味着变量类型由它初始化的表达式类型决定(在本例中,它是 int,因为这是文字类型 0)。也就是说,

auto i = 0;

相当于:

int i = 0;

片段

auto i;
i = 0;

没有意义,因为没有编译器可以从中推断出类型的表达式。

有人可能会争辩说,编译器可以进一步推导类型,但这将是额外的努力,价值很小,因此它不太可能进入未来的 C++ 标准。在以下示例中将推断出什么类型:

auto i;
if (...)
    i = 0;
else
    i = "WAT?";

顺便说一句,int i = 0; 等同于 int i; i = 0 但并不相同。首先是初始化,其次是默认初始化,然后是赋值。对于 int 以外的类型,即具有非平凡构造函数 and/or 赋值运算符的 类,这两个片段可能不等价。

7.1.6.4 自动说明符 部分中的 draft 有此条目

The auto and decltype(auto) type-specifiers are used to designate a placeholder type that will be replaced later by deduction from an initializer.

因此,autodecltype(auto) 需要一个 初始化器

auto i = 0; // ok, i is of type "int" deduced from 0's type

等同于

int i = 0;

但是

auto i; // error: no initializer, compiler fails to deduce type
i = 0;  // error: consequent error, i not declared/defined

将无法编译,因为编译器无法在没有初始化程序的情况下推断出 i 的类型。
还有,

int i = 0; // initialized i as 0

不同于

int i; // default initialized
i = 0; // invokes copy assignment

是的,由于使用的特定类型,以下两个在允许的情况下是等效的。
第二个is forbidden in constexpr-functions though ( @T.C.):

int i = 0;

int i;
i = 0;

虽然他们使用不同的方式到达那里(copy-initialization vs. default-initialization degenerating to no-initialization combined with assignment), the as-if-rule意味着他们是等价的。如果我们谈论不同的非平凡类型,情况可能会有所不同。

现在,如果我们用 auto 代替 int,事情会变得更复杂:
我们不再命名变量的具体类型,而是 we let the compiler deduce it.

并且标准声明它只会从初始化器中推导出它,初始化器必须是声明的一部分。
它可以很容易地看起来稍微远一点,也许至少 the way return-type-deduction 适用于 lambdas 和 C++14 函数,这意味着第一个赋值。
或者它甚至可以尝试从所有使用它的地方合成一个兼容的类型,就像其他一些语言那样,但这会使规则复杂化很多。

无论如何,该标准不允许这样做,并且它对什么是 C++ 和什么不是 C++ 有最终决定权,所以直到并且除非有人向委员会提出令人信服的理由在语言的下一个版本。

当用auto定义变量时,必须为其分配一个初始值。否则将无法确定其类型,因为声明为 auto 的变量的类型是由编译器静态 确定的。

C++11 标准:

7.1.6.4 auto specifier

...

3 Otherwise, the type of the variable is deduced from its initializer. The name of the variable being declared shall not appear in the initializer expression.

auto i 并不意味着“i 可以容纳任何东西,所以不要担心它是什么类型”。 C++ 要求在创建对象时必须知道任何对象的类型。当您编写 auto i = something; 时,编译器会查看 something 的类型,以确定 i 的类型应该是什么。如果没有 something,则没有任何信息可以告诉编译器 i 的类型应该是什么,并且会出现错误。

int i;
i = 0;

int i=0;

给出相同的可观察结果,但它们等价。前者先声明一个变量然后赋值给它,后者声明一个变量然后初始化它。所以它实际上等同于 int i(0);

如果您使用更复杂的 类 而不是普通整数,前一个代码将调用 operator =,而后者将调用一个复制(或移动)构造函数。

这就是为什么 auto i=0; 有意义的原因:它定义了一个变量 i,其类型与它的初始值设定项(这里是一个普通的 int)相同。但是 auto i; 会引发编译错误,因为在编译器处理声明时,它不知道类型应该是什么。