指向函数的指针有时/总是?是函数声明符吗?

问题描述

(这个问题是从the discussion to this answer中分离出来的,重点是CWG 1892


该标准的某些段落将特定规则应用于函数声明符;例如[dcl.spec.auto]/3 关于占位符类型 [重点 我的]:

占位符类型可以在decl-specifier-seqtype-specifier-seq中与函数声明符一起出现转换函数 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}} 根据 [dcl.spec.auto]/4 关于从初始值设定项推导的变量类型)?

什么是给定声明符的规则并不完全容易遵循,但我们可以注意到,从 [dcl.decl]/1

声明符在声明中声明单个变量、函数或类型。

给定的声明符是变量声明符函数声明符类型声明符中的任何一种。

  • [dcl.ptr] 涵盖了作为指针的(变量)声明符,但没有明确(/规范地)提及指向函数的指针,尽管在 [dcl.ptr]/4 中以非规范方式这样做了
  • [dcl.fct] 涵盖了函数声明符,但没有提到函数指针作为函数声明的一部分,只是指出在函数指针的赋值/初始化期间检查函数类型(这与函数声明符是什么无关) )

我的解释是 #1 是合法的(根据当前标准),因为它属于变量声明符。如果这实际上是正确的,那么扩展问题(来自链接的线程)是

#1

是否合法(/根据 CWG 1892 是否合法);因为模板参数可以说包含一个声明符,它是一个函数指针声明符,而不是一个函数声明符。

我们终于可以注意到,正如链接到答案中所指出的那样,

template<auto (*g)()> 
int f() { return g(); }

可以说是格式错误的(尽管这个例子也被 GCC 和 Clang 接受),因为 template<auto g()> // #2 int f() { return g(); } 处的非类型模板参数是一个函数声明符,因此根据 [ dcl.spec.auto]/3,因为它不包含尾随返回类型并且不声明函数

解决方法

此处的混淆源于“声明符”的两种不同含义:一种是声明中与一个实体(或 typedef-name)相关的部分(在说明符之后),而另一种是是用于形成前一种的几种句法结构中的任何一种。后一种含义产生了语法产生式ptr-declarator(也包括引用)和noptr-declarator(包括函数和数组)。该含义对于赋予“函数声明者应声明函数”的限制具有任何含义也是必要的。此外,如果我们采用变量声明

auto (*g)() = /*…*/;

为了 [dcl.spec.auto.general]/3 的目的不涉及“函数声明符”,我们将无法编写

auto (*g)() -> int;

这是普遍接受的(就像问题中的类似例子一样)。

此外,虽然检查“函数声明符是否包含trailing-return-type”的语句不可避免地指的是整体声明符 (这是支持 trailing-return-type 的原因),它以“声明运算符”的身份这样做,因为它仍然允许嵌套使用此类运算符的上述情况。 (该限制所禁止的只是

auto *f() -> int*;

在那里演绎可以工作但在这里根本不执行,因为它总是没用的。)

与此同时,有一些证据表明,除了实现共识之外,更高级别问题的答案是在这些情况下auto应该被允许:[dcl.spec.auto .general]/1 表示函数参数中的 auto 用于声明泛型 lambda 或缩写函数模板“如果它不是 auto type-specifier 引入 trailing-return-type" 而不是如果它根本不与函数声明符一起使用。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...