【问题标题】:Where in the Standard does it say that the declaration `auto f()() ->int;` is not allowed?标准中哪里说不允许声明“auto f()()->int;”?
【发布时间】:2015-01-22 18:05:43
【问题描述】:

我知道我在这里很迂腐,但我只是想了解 C++ 语法产生。

我将从简单声明开始。

简单声明
decl-specifier-seqopt   init-declarator-listopt

decl-specifier-seq:
decl-说明符

decl-specifier:
类型说明符

类型说明符
尾随类型说明符

尾随类型说明符
简单类型说明符

简单类型说明符
字符
整数
...
自动


现在,我将研究 init-declarator-list 的定义。

init-declarator-list:
初始化声明器

初始化声明符
声明符

声明符
noptr-declarator   参数和限定符   尾随返回类型    (*2)

noptr 声明符
declarator-id   attribute-specifier-seqopt
noptr-declarator   参数和限定符    (*1)

参数和限定符
(parameter-declaration-clause)   cv-qualifiersopt   ...(所有选项)

尾随返回类型
->   尾随类型说明符序列

尾随类型说明符序列
trailing-type-specifier               参见上面的trailing-type-specifier的定义。


(*1)中用declarator-id替换noptr-declarator,使用noptr-declaration的先前定义,我们得出以下nonptr-declarator的定义:

noptr 声明
declarator-id   参数和限定符

现在替换 (*2) 中的 noptr-declaratorparameters and qualifierstrailing-return-type > 根据上面给出的每个定义,我们为 declarator 获得以下内容:

声明符
declarator-id   (parameter-declaration-clause)   (parameter-declaration-clause)   ->
简单类型说明符


根据最后一个结果,我们可以说语法允许以下函数声明f

auto f()() -> int;  

这当然是无效的。但我在标准中找不到任何直接或间接说明这种结构不正确的内容。

来自GCCf 声明为返回函数的函数)和clangauto 返回没有尾随返回类型;推断的返回类型是 C++1y 扩展)的错误消息没有帮助在这方面也是。

【问题讨论】:

  • 这是不允许的,因为标准中没有描述这种语法的语法。这就像说int f(){} * 100 是不允许的,但我在标准中没有找到任何不允许它的东西。
  • 你在这里掩盖了真正的错误,它试图定义一个返回函数的函数。 int f()() 同样无效。
  • 您如何到达auto f()() -> int; ?你说“有了最后一个结果,我们可以....”
  • @POW 在简单声明中,使 simple-type-specifier = auto。然后使 declarator-id = f,依此类推。

标签: c++ c++11 language-lawyer


【解决方案1】:

[dcl.fct]/8:

[...] 函数不应具有类型数组或函数的返回类型,尽管它们可能具有类型指针或对此类事物的引用的返回类型。 [...]

【讨论】:

  • @ecatmur 这可以解释GCC 发出的错误,但我不明白这与声明auto f()() -> int; 有什么关系
  • @Ayrosa 假设 auto f()()->int 有效。那么它的含义与int f()() 相同。 int f()() 是什么?函数 f() 返回函数 int _()auto _()->int。展开解析树,并标记每个组件。
  • @Yakk 所以本质上你是说我们可以将它重写为int (f())(); 这是......一个返回函数的函数?如果我们在f() 之前添加&*,我们会分别得到一个指针或引用?
  • @Columbo 是的,我想是的。并且至少 clang 同意——auto (*f())()->int 编译并且是与int (*f())() 相同类型的函数。然而,我并没有真正扩展解析树的乐趣,所以很容易出错。
【解决方案2】:

事实上,gcc 错误信息很有帮助:语法确实允许auto f()() -> int,但是这个语法正确的声明在语义上是无效的。它将描述一个函数返回一个返回int 的函数。有关不允许这样做的标准报价,请参阅 ecatmur 的答案。

要理解解析,像这样工作。 f 是您要声明的内容。向右解析,你会发现一个空的参数列表,所以f() 是一个有效的表达式,并且该表达式的类型被声明。再次向右解析,你会发现一个参数列表再次,所以f 的返回类型是一个带零参数的函数。再次向右解析,您将到达末尾(-> 箭头),因此向左解析以找到结果类型,即 auto,并被箭头后面的类型替换。

【讨论】:

  • live example 的函数返回指向 auto()->int 类型函数的指针。我只添加了一些围绕子表达式的(),而* 表示某事是一个指针。 auto (*f())() -> int.
  • 我接受您的回答,因为您在上面的第二段中准确描述了我所缺少的内容(请参阅我对 ecatmur 的评论)。很好的答案 (+1)。