【问题标题】:Why can the return type of main not be deduced?为什么main的返回类型不能推导出来?
【发布时间】:2016-12-30 14:44:38
【问题描述】:

正如预期的那样,以下在 C++11 中失败了,因为该语言没有 bog 标准函数的返回类型推导:

auto main()
{
   return 0;
}

但是,C++14 可以,所以我无法解释以下错误(在 GCC 主干、clang 3.8 和 Visual Studio 2015 中具有相同的结果):

error: 'main' must return 'int'

标准中是否有一段我没有看到,禁止main 的返回类型扣除?还是两个编译器都不兼容?

(对于它的价值,我永远不会真正这样做。int main() 为胜利......)

【问题讨论】:

  • 我也能够在 Visual Studio 中重现这一点。
  • @Xirema:谢谢! 2015,我猜?
  • 如果主函数中有多个return 语句返回不同类型(int、double 等)的数据怎么办?
  • @iammilind:我不会与复制品作斗争,但这并不“准确”。对于初学者,运行一个差异:你会发现很多字符不同。更广泛地说,有人问main 的返回类型是否“将”在 C++14 中推导出来......而这个问题从答案应该是“是”的前提开始,询问为什么各种编译器都会给出结果与那个答案形成鲜明对比。他们有错误吗,还是有其他原因?不幸的是,前提是有缺陷的,因为我错误地使用了过时的草稿,所以这一切都没有实际意义。

标签: c++ c++14 return-type-deduction


【解决方案1】:

阅读the C++17 draft§3.6.1/2:

...它应该有一个声明的返回类型int, ...

所以是的,我会说禁止使用扣除。


the last C++14 draft 中的措辞几乎完全相同(与 C++17 草案相同的部分):

它应该有一个声明的返回类型int, ...


在阅读 cmets 和其他答案后,个人对 可能 原因的反思。不允许推理返回类型推导是(我认为)因为编译器在看到return 语句之前不知道返回类型。可能返回其他类型(隐式可转换为int)的情况也很常见,这会使推导的类型错误。预先声明返回类型(通过普通的老式方式,或使用尾随返回类型)将在声明函数时设置类型,并且可以由编译器检查是否正确。

至于允许类型别名,它们只是类型的别名。所以允许例如

typedef int my_type;
my_type main() { ... }

真的和

没什么区别
int main() { ... }

【讨论】:

  • 所以在这段代码中声明的返回类型是MyType,而不是inttypedef int MyInt; MyInt main() { },但是clang和gcc接受。有什么原因吗?
  • N4296 不是“最后的 C++14 草案”。这是第一个包含折叠表达式的 C++17 草案。 C++14 DIS为N3937(N3936内容相同但封面不同); IS 是 N4141(N4140 是 IS + 编辑修复)。
  • @T.C.这不是 isocpp.org website says 的内容:“这个工作草案包含 C++14 标准以及少量的编辑更改。”
  • 如果有人有高音扬声器,他们可以发送到@isocpp,让他们知道错误
  • 至于基本原理,this comment from Richard Smith 是相关的。
【解决方案2】:

从 3.6.1/2 开始(重点是我的):

[...]它应该有一个int 类型的声明的返回类型,否则它的类型是实现定义的。

auto 不带尾随返回类型使用时,函数的声明的返回类型仍然是auto,即使推导的返回类型可以是别的东西。 declareddeduced 之间的区别在标准中没有明确说明,但 7.1.6.4/7 可能会有所启发:

当 [...] return 语句出现在使用包含占位符类型的返回类型声明的函数中时,推导的返回类型 [...] 由其初始化程序的类型确定。对于没有操作数的return 或具有void 类型的操作数,声明的返回类型应为auto,推导的返回类型为void

我的理解是这样的:

auto main(){ return 0; }

声明的返回类型仍将是auto,尽管推导的返回类型将是int。根据上述 3.6.1/2,main声明的返回类型必须int。因此,这是格式错误的。

但是,尾随返回类型被视为声明的返回类型。从 7.1.6.4/2 开始:

如果函数声明符包含 trailing-return-type (8.3.5),则 trailing-return-type 指定函数的声明返回类型。

$ cat a.cpp
auto main() -> int {}
$ g++ -Wall -std=c++14 a.cpp
$

所有引号在 C++14 和 C++17 中都是相同的。

【讨论】:

  • 真正的问题是为什么从 return 语句中推断出的类型没有指定函数声明的返回类型。
  • @Random832 我已经更新了我的答案,虽然对于为什么没有真正的答案。
【解决方案3】:

从 3.6.1 [basic.start.main]

1 程序应包含一个名为 main 的全局函数,它是 指定程序的开始....
2 一个实现不得 预定义主函数。该功能不得重载。它 应具有声明的返回类型为 int 类型,否则为它的类型 是实现定义的...

如果标准是限制扣除,那么我认为“声明返回类型 int”的措辞就是它。

【讨论】:

  • 这是从 N4296 开始的 C++14 的措辞(我手头的草稿)
  • 啊,你说得对——我的草稿太旧了。我以为是FDIS。 :(
【解决方案4】:

许多答案都很好地提到了标准中的引用。但是auto 作为返回类型还有另一个微妙的问题。

根据 C++ 标准 (somewhere),main() 内的 return 语句不是强制性的。这在 Bjarne Stroustrup 的 website 中明确提到:

在 C++ 中,main() 不需要包含显式的 return 语句。在这种情况下,返回值为0,表示执行成功。

这意味着下面的陈述是有效的:

auto main () {}

可以假设在} 之前有一个隐含的return 0; 语句。所以在这种情况下auto解释为 int。但是,从 C++14 的技术角度来看,auto 必须推导出 void,因为没有返回语句!那么,“intvoid”,应该考虑什么?

IMO 这是一个警告,它也阻止了 auto 作为逻辑意义上的返回类型。

【讨论】:

  • “这意味着下面的陈述是有效的” 我不遵循你的推理。显然你不能在没有返回语句的情况下使用返回类型推导。这绝不意味着当您确实编写 return 语句时,它不应该能够使用返回类型推导,就像任何其他函数一样。
  • @Light,你写道:“显然你不能在没有返回语句的情况下使用返回类型推导”。这不是真的。当然我们可以推断出return 类型没有return 声明! Demo。当没有返回类型时,它被推断为void,如那里所示。你剩下的句子不清楚。无论如何,如果有帮助,您可以尝试关注链接的骗子。
  • (除非你想推演void)* 剩下的那句话很清楚,但不知道你对它的哪一部分感到困惑,我无能为力。
【解决方案5】:

正如在各种 cmets 中所讨论的,我确实在标准中遗漏了它,因为我认为是 C++14 FDIS 的副本实际上不是这样的东西(而是一个稍微旧的草案),并且在CWG 1669之后的相关段落中隐藏了“声明”一词。

【讨论】:

  • 这并没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review
  • @miken32:这肯定是一个答案,我不太可能要求自己澄清。
  • 在 1669 上发现不错。
  • this answer 上也提到过。如果我足够勇敢,我会将这个问题标记为重复 :)
  • @iammilind:是的,它确实一个答案,正如差不多一个月前所讨论的那样。你有什么有用或有建设性的东西要补充吗?
猜你喜欢
  • 2016-11-09
  • 1970-01-01
  • 2023-03-18
  • 2014-10-09
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多