指向函数 (sometimes/always?) 的指针是函数声明符吗?

Is a pointer to function (sometimes/always?) a function declarator?

(此题已从, which highlights CWG 1892中分出)


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

The placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type ([dcl.fct]), that trailing-return-type specifies the declared return type of the function. Otherwise, the function declarator shall declare a function. [...]

限制占位符类型可以与(在)函数声明符一起出现的位置。我们可以研究下面的例子:

int f() { return 0; }
auto (*g)() = f;  // #1

GCC 和 Clang 都接受,将 g 推导为 int(*)()


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

A declarator declares a single variable, function, or type, within a declaration.

给定的声明符是变量声明符函数声明符类型声明符.

我的解释是 #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,因为它不包含尾随 return 类型并且不声明函数。

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

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

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

auto (*g)() -> int;

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

此外,检查“函数声明符是否包含 trailing-return-type”的语句不可避免地引用 overall declarator(支持 trailing-return-type),它以其作为“声明运算符”,因为它仍然允许在上述情况下嵌套使用此类运算符。 (该限制禁止的只是

auto *f() -> int*;

推导会起作用,但在这里根本不执行,因为它总是没用。)

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