问题
(This question has been broken out from the discussion to this answer, which highlights CWG 1892)
Some paragraphs of the standard applies specific rules to function declarators; e.g. [dcl.spec.auto]/3 regarding placeholder types [emphasis mine]:
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. [...]
restricts where placeholder types may appear with(in) a function declarator. We may study the following example:
int f() { return 0; }
auto (*g)() = f; // #1
which both GCC and Clang accepts, deducing g
to int(*)()
.
- Is a pointer to function (sometimes/always?) a function declarator?
- Or, alternatively, applied to the example, should
#1
be rejected as per [dcl.spec.auto]/3, or does the latter not apply here as a pointer to function is not a function declarator (instead allowing#1
as per [dcl.spec.auto]/4 regarding variable type deduction from initializer)?
The rules for what is a given declarator is not entirely easy to follow, but we may note that, from [dcl.decl]/1
A declarator declares a single variable, function, or type, within a declaration.
that a given declarator is either any of a variable declarator, a function declarator or a type declarator.
- [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] covers function declarators but does not mention function pointers as part of function declarations, other than a note that function types are checked during assignment/initialization to function pointers (which is not relevant for what a function declarator is)
My interpretation is that #1
is legal (as per the current standard), as it falls under a variable declarator. If this is actually correct, then the extended question (from the linked thread) is whether
template<auto (*g)()>
int f() { return g(); }
is legal or not (/intended to be legal or not as per CWG 1892); as the template parameter arguably contains a declarator that is a function pointer declarator, and not a function declarator.
We may finally note, as similarly pointed out in the linked to answer, that
template<auto g()> // #2
int f() { return g(); }
is arguably ill-formed (although this example is also accepted by both GCC and Clang), as the non-type template parameter at #2
is a function declarator and is thus used in an illegal context as per [dcl.spec.auto]/3, as it does not contain a trailing return type and does not declare a function.
回答1:
The confusion here arises from two different meanings of "declarator": one is the portion of a declaration (after the specifiers) that pertains to one entity (or typedef-name), while the other is any of the several syntactic constructs used to form the former kind. The latter meaning gives rise to the grammar productions ptr-declarator (which also covers references) and noptr-declarator (which includes functions and arrays). That meaning is also necessary to give any meaning to a restriction that a "function declarator shall declare a function". Moreover, if we took the variable declaration
auto (*g)() = /*…*/;
to not involve a "function declarator" for the purposes of [dcl.spec.auto.general]/3, we would not be able to write
auto (*g)() -> int;
which is universally accepted (just as is the similar example in the question).
Moreover, while the statement that checks whether "the function declarator includes a trailing-return-type" inevitably refers to an overall declarator (which is what supports a trailing-return-type), it does so in its capacity as a "declaration operator" because it still allows the above cases with nested use of such operators. (What that limitation forbids is just
auto *f() -> int*;
where deduction would work but isn't performed at all here because it would always be useless.)
Meanwhile, there is some evidence, beyond implementation consensus, that the answer to the higher-level question is that auto
in these cases should be allowed: [dcl.spec.auto.general]/1 says that auto
in a function parameter serves to declare a generic lambda or abbreviated function template "if it is not the auto
type-specifier introducing a trailing-return-type" rather than if it is not used with a function declarator at all.
来源:https://stackoverflow.com/questions/66009034/is-a-pointer-to-function-sometimes-always-a-function-declarator