对'auto'扣除类型的困惑

Confusion about 'auto' deduction type

本文关键字:类型 auto      更新时间:2023-10-16
int i = 0;

相当于

int i;
i = 0;

然后

auto i = 0;

没关系,工作正常。但

auto i;
i = 0;

编译器给出错误。

那么,为什么编译器会给出错误?

它不等效,因为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以外的类型,即具有非平凡构造函数和/或赋值运算符的类,这两个代码段可能不等效。

第 7.1.6.4 节自动说明符中的草稿有此条目

auto

和 decltype(auto) 类型说明符用于指定 占位符类型,稍后将通过从 初始 化。

因此,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

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

auto i;
i = 0;

将不起作用,因为auto从其初始值设定项推断出i的类型,在这种情况下,您没有初始值设定项

另一方面,这有效:

auto i = 0;

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

代码

auto i;
i = 0;

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

文档

  • 自动类型
  • 参数类型推导

自动类型需要由编译器推断,一旦类型设置,就无法更改。这是一个编译时操作。因此,它需要初始化。这实际上是其中的重点,通过将所有内容移动到 = 的右侧来确保变量初始化

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

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

C++11标准:

7.1.6.4 自动说明符

3 否则,变量的类型是从其初始值设定项推导出来的。 要声明的变量的名称不应出现在 初始值设定项表达式。

是的,由于使用的特定类型,以下两个在允许的情况下是等效的。
第二个在constexpr函数中是被禁止的(谢谢@T.C.):

int i = 0;
int i;
i = 0;

尽管它们使用不同的方法来到达那里(复制初始化与默认初始化退化为无初始化结合赋值),但假设规则意味着它们是等效的。如果我们谈论不同的非平凡类型,情况可能会有所不同。

现在,如果我们用auto代替int,事情会变得更加复杂:
我们不再命名变量的具体类型,而是让编译器推断它。

并且该标准声明它只会从初始值设定项中推断它,该初始值设定项必须是声明的一部分。
它可以很容易地看得更远一点,也许至少是返回类型推导对 lambda 和 C++14 函数的工作方式,这意味着第一个赋值。
或者它甚至可以尝试从所有使用它的地方合成兼容的类型,就像其他一些语言所做的那样,但这会使规则变得非常复杂。

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

int i;
i = 0;

int i=0;

给出相同的可观察结果,但它们并不等效。前者首先声明一个变量并为其赋值,后者声明一个变量并对其进行初始化。所以它实际上相当于int i(0);

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

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