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

风流意气都作罢 提交于 2021-02-09 05:10:57

问题


(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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!