对'auto'扣除类型的困惑
Confusion about 'auto' deduction type
int i = 0;
相当于
int i;
i = 0;
然后
auto i = 0;
没关系,工作正常。但
auto i;
i = 0;
编译器给出错误。
那么,为什么编译器会给出错误?
它不等效,因为auto
不是一个类型。在这两个示例中,i
类型都是int
。auto
表示变量类型由初始化它的表达式类型确定(在这种情况下,它是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) 类型说明符用于指定 占位符类型,稍后将通过从 初始 化。
因此,auto
和decltype(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
的类型无法在编译时确定,因为没有像前面的示例那样的直接赋值,因此编译器将不知道用什么来代替auto
i
。在第一个示例中,您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;
会引发编译错误,因为在编译器处理声明时,它不知道类型应该是什么。
- 推理类型如何工作"auto"和按引用调用?
- 将函数参数类型声明为 auto
- 使用constexpr + auto作为返回和参数类型的奇怪类型推导
- 使用"auto"推断嵌套初始值设定项列表的类型
- "auto"推断出 hashtable_policy.h 中的错误类型
- 为什么"const auto [x, y]"绑定到引用类型时没有按预期运行?
- 对'auto'扣除类型的困惑
- 如果使用返回引用的函数初始化"auto"var,为什么它不声明引用类型?
- decltype(auto) 是否使尾随返回类型过时?
- 用 decltype 和 auto 推导出 const(返回)类型
- 警告:函数使用不带尾随返回类型的'auto'类型说明符
- 在 Objective-C++ 中应用于__weak指针时,通过关键字推导类型"auto"规则是什么?
- decltype(auto) 类型演绎:返回 x 与返回 (x)
- C++:在原型中声明"auto"函数返回类型仍然会导致在扣除错误之前使用"auto&quo
- 我可以在动态知道其类型的模板类对象中使用 auto 关键字吗?我不能在没有初始值设定项的情况下使用 auto 关键字吗?
- C++14 'auto'能够获取函数返回类型,我们还需要 std::result_of<> 吗?
- 声明适用于 auto,但不能显式声明类型?
- 如何在编译时决定'auto'返回类型?
- 为什么在auto和template函数的情况下,类型都没有推导为"const"类型
- 调用的对象类型'auto'不是函数或函数指针