【问题标题】:Confusion about 'auto' deduction type关于“自动”扣除类型的困惑
【发布时间】:2017-08-04 08:47:54
【问题描述】:
int i = 0;

等价于

int i;
i = 0;

那么,

auto i = 0;

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

auto i;
i = 0;

编译器报错。

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

【问题讨论】:

  • 您的最后一个 sn-p 显然无效,编译器将如何尝试推断类型?一旦你声明了一个变量,编译器需要知道足够的知识来推断类型、存储和大小。输入auto i时没有信息
  • 前两个代码 sn-ps 并不完全等价,它们只是对ints 有类似的效果。如果它是具有用户定义的构造函数和赋值运算符的类类型,结果可能会完全不同。
  • int i = 0; 不等同于int i; i = 0;。第一个定义i 并使用0 的值对其进行初始化。第二个定义i,没有初始化,然后赋值给0
  • @EdChum:简单地说,编译器可以查看块的其余部分来确定变量类型或完全丢弃它。其他语言这样做,C++ 决定采用更简单的模型。
  • @Deduplicator 在constexpr 函数中允许使用一个;另一个不是。

标签: c++ c++11 types auto


【解决方案1】:

它不等价,因为auto 不是一个类型。在这两个示例中,i 类型都是 intauto 表示变量类型由初始化它的表达式类型确定(在这种情况下,它是 int,因为这是文字 0 的类型)。也就是说,

auto i = 0;

相当于:

int i = 0;

sn-p

auto i;
i = 0;

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

有人可能会争辩说,编译器可以进一步推导类型,但这会付出额外的努力而没有什么价值,因此它不太可能在未来的 C++ 标准中占据一席之地。在下面的例子中会推断出什么类型:

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

顺便说一句,int i = 0; 等价于 int i; i = 0 但不一样。首先是初始化,其次是默认初始化,然后是赋值。对于int 以外的类型,即具有非平凡构造函数和/或赋值运算符的类,两个 sn-ps 可能不等价。

【讨论】:

  • 好吧,他们(int i = 0;int i; i = 0; 是等价的,尽管只是在经过大量冗长的工作之后。 as-if-rule 不仅适用于编译器,也适用于解释自然语言。
  • @Deduplicator 它们在“编译器最有可能发出相同的机器代码”的意义上是等价的,但在语言语法规则方面并不等价。尤其是当泛化到 int 以外的类型时,这些表达式可能在任何意义上都不等价。
  • 所以,你承认它们是等价的,但坚持只看一些可能不再适用的概括。不仅仅是说使用这个和那个泛化它们不再等价。
  • @Deduplicator - el.pescado 提到的“一些概括”,你正在愉快地驳回,实际上是由 C++ 标准描述的。这就是您在与此问题相关的 cmets 中反复未能承认的一点。该标准定义了语言,包括各种结构和结构组合的含义,而不是任何编译器的输出。
  • 这种特殊情况中,类型是int,赋值就是下一条语句,可检测的效果总是相同的。这就是 @Deduplicator 的观点,即适用于自然语言的 as-if 规则。如果类型是MyClass,或者赋值没有立即跟在初始化之后,那么它们就不是等价的。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:
      auto i;
      i = 0;
      

      由于auto 从它的初始化程序推导出i 的类型,因此无法工作,在这种情况下,您没有初始化程序

      另一方面,这是可行的:

      auto i = 0;
      

      因为现在你确实有一个初始化器 - 0 - 因为文字 0 的类型是 int 这就是 auto 推导出 i 的类型.

      【讨论】:

        【解决方案5】:

        代码

        auto i;
        i = 0;
        

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

        文档

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

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

              C++11 标准:

              7.1.6.4 自动说明符

              ...

              3 否则,变量的类型是从它的初始化器推导出来的。 被声明的变量名不能出现在 初始化表达式。

              【讨论】:

              • 您的粗体文本“必须为其分配一个初始值”不正确。它必须被初始化。它们是不同的东西,即使语法看起来很相似(并且可以使用= 字符)。
              【解决方案9】:

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

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

              虽然他们使用不同的方式到达那里(copy-initializationdefault-initialization 退化为无初始化结合赋值),as-if-rule 表示它们是等价的。如果我们谈论不同的非平凡类型,情况可能会有所不同。

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

              并且标准规定它只会从初始化程序中推断出它,它必须是声明的一部分。
              它可以轻松地看起来更远一些,也许至少 the way return-type-deduction 适用于 lambdas 和 C++14 函数,这意味着第一次分配。
              或者它甚至可以尝试从所有使用它的地方合成一个兼容的类型,就像其他一些语言那样,但这会使规则变得相当复杂。

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

              【讨论】:

              • 不,两者不等价。是的,它们实现了相同的净效果(定义了一个变量 i,随后其值为 0),但它们到达那里的方式不同。
              • @Peter:不要将它们是否以相同的方式到达那里与它们是否等效相混淆。假设规则的存在是有原因的!
              • 它们可能等效。这是一种危险的心理模型,因为它不适用于某些类型和某些编译器。
              • @Caleth:等价是等价的。是的,它不适用于许多其他更有趣的类型,但它确实适用于琐碎的类型。这就是我阐明它们达到相同的方式的原因,而不是仅仅陈述赤裸裸的事实。
              • “假设”规则不要求将它们编译为相同的目标代码。它只允许它。
              【解决方案10】:
              int i;
              i = 0;
              

              int i=0;
              

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

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-01-06
                • 2015-10-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-03-21
                相关资源
                最近更新 更多