指向函数 (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(*)()
。
- 函数指针 (sometimes/always?) 是函数声明符吗?
- 或者,或者,应用于该示例,应该
#1
根据 [dcl.spec.auto]/3 被拒绝,或者后者不适用于此处,因为指向函数的指针不是函数声明符(而是允许#1
根据 [dcl.spec.auto]/4 关于从初始化程序中推导变量类型)?
给定声明符的规则并不完全容易遵循,但我们可能会注意到,从 [dcl.decl]/1
A declarator declares a single variable, function, or type, within a declaration.
给定的声明符是变量声明符、函数声明符或类型声明符.
- [dcl.ptr] covers (variable) declarators that are pointers, but does not explicitly (/normatively) mention pointers to functions, albeit does so non-normatively in [dcl.ptr]/4
- [dcl.fct] 涵盖了函数声明符,但没有提及函数指针作为函数声明的一部分,除了注意在 assignment/initialization 期间检查函数类型到函数指针(这与什么无关函数声明符是)
我的解释是 #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" 而不是如果它根本不与函数声明符一起使用。
(此题已从
标准的某些段落将特定规则应用于函数声明符;例如[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(*)()
。
- 函数指针 (sometimes/always?) 是函数声明符吗?
- 或者,或者,应用于该示例,应该
#1
根据 [dcl.spec.auto]/3 被拒绝,或者后者不适用于此处,因为指向函数的指针不是函数声明符(而是允许#1
根据 [dcl.spec.auto]/4 关于从初始化程序中推导变量类型)?
给定声明符的规则并不完全容易遵循,但我们可能会注意到,从 [dcl.decl]/1
A declarator declares a single variable, function, or type, within a declaration.
给定的声明符是变量声明符、函数声明符或类型声明符.
- [dcl.ptr] covers (variable) declarators that are pointers, but does not explicitly (/normatively) mention pointers to functions, albeit does so non-normatively in [dcl.ptr]/4
- [dcl.fct] 涵盖了函数声明符,但没有提及函数指针作为函数声明的一部分,除了注意在 assignment/initialization 期间检查函数类型到函数指针(这与什么无关函数声明符是)
我的解释是 #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" 而不是如果它根本不与函数声明符一起使用。