【发布时间】:2021-02-02 11:42:24
【问题描述】:
(此问题已从the discussion to this answer 拆分出来,其中突出显示CWG 1892)
标准的某些段落将特定规则应用于函数声明符;例如[dcl.spec.auto]/3 关于占位符类型 [emphasis mine]:
占位符类型可以出现在decl-specifier-seq、type-specifier-seq、中的函数声明符 Conversion-function-id 或 trailing-return-type,在此类声明符有效的任何上下文中。如果函数声明符包含 trailing-return-type ([dcl.fct]),则 trailing-return-type 指定函数的声明返回类型。 否则,函数声明器应该声明一个函数。 [...]
限制占位符类型与函数声明符一起出现的位置。我们可以研究下面的例子:
int f() { return 0; }
auto (*g)() = f; // #1
GCC 和 Clang 都接受,将 g 推导出为 int(*)()。
- 指向函数的指针(有时/总是?)是函数声明符吗?
- 或者,或者,应用于该示例,是否应该根据[dcl.spec.auto]/3 拒绝
#1,或者后者在此处不适用,因为指向函数的指针不是函数声明符(而是允许#1根据@ 987654325@关于从初始化程序中推导变量类型)?
给定声明符的规则并不完全容易遵循,但我们可能会注意到,来自[dcl.decl]/1
声明器在声明中声明单个变量、函数或类型。
给定的声明符是变量声明符、函数声明符或类型声明符中的任何一个。
- [dcl.ptr] 涵盖作为指针的(变量)声明符,但没有明确(/规范地)提及函数的指针,尽管在 [dcl.ptr]/4 中这样做是非规范的
- [dcl.fct] 涵盖了函数声明符,但没有提及函数指针作为函数声明的一部分,除了注意在函数指针的赋值/初始化期间检查函数类型(这与函数声明符无关)
我的解释是#1 是合法的(根据当前标准),因为它属于变量声明符。如果这实际上是正确的,那么扩展的问题(来自链接的线程)是是否
template<auto (*g)()>
int f() { return g(); }
是否合法(/根据 CWG 1892 是否合法);因为模板参数可以说包含一个声明符,它是一个函数指针声明符,而不是一个函数声明符。
我们最终可能会注意到,正如链接到答案中同样指出的那样,
template<auto g()> // #2
int f() { return g(); }
可以说是格式错误的(尽管这个例子也被 GCC 和 Clang 接受),因为#2 处的非类型模板参数是一个函数声明符,因此根据 [dcl. spec.auto]/3,因为它不包含尾随返回类型,也不声明函数。
【问题讨论】:
-
我的理解是
auto (*g)() = f;工作的原因与auto x = 42;工作的原因相同,而不是因为它与函数有关。其实one can writeauto x = 42, (*g)() = f; -
@IgorTandetnik 为了清楚起见:我们讨论的是格式良好的,而不是有效的(这些在语言律师问题中通常存在冲突)。我也倾向于
auto (*g)() = f格式正确,关键是它的声明中没有函数声明符(这样 [dcl.spec.auto]/3 不适用)。你的第二个例子是[dcl.decl]/3,在这里并不重要;所讨论的单个声明符是格式正确的还是格式错误的(单独或作为带有多个声明符的声明的一部分)。 -
它的声明中没有函数声明符 那么
auto (*g)()是如何解析的呢? -
@LanguageLawyer "倾向于 [...] 没有函数声明符" - 这是我的关键问题:这里实际上涉及函数声明符吗? / 是指向函数的指针,还是包含函数声明符?如果您有“是/确实”的论据,请考虑发布答案。 (在这种情况下 [dcl.spec.auto]/3 可能适用,暗示
#1格式不正确?)。 -
这里实际上有一个函数声明器吗? / 是指向函数的指针,还是包含函数声明符? 我不知道如何在没有 [dcl.fct] 的情况下解析
auto (*g)()。auto (*g)()的形式为T D1()。
标签: c++ language-lawyer auto type-deduction