This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-11-11
[Voted into the WP at the September, 2008 meeting as part of paper N2757.]
The wording added to 9.3.4.6 [dcl.fct] for declarators with late-specified return types says,
In a declaration T D where D has the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt exception-specificationopt -> type-id
and the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T,” T shall be the single type-specifier auto and the derived-declarator-type-list shall be empty.
These restrictions were intended to ensure that the return type of the function is exactly the specified type-id following the ->, not modified by declarator operators and cv-qualification.
Unfortunately, the requirement for an empty derived-declarator-type-list does not achieve this goal but instead forbids declarations like
auto (*fp)() -> int; // pointer to function returning int
while allowing declarations like
auto *f() -> int; // function returning pointer to int
The reason for this is that, according to the grammar in 9.3 [dcl.decl] paragraph 4, the declarator *f() -> int is parsed as a ptr-operator applied to the direct-declarator f() -> int; that is, the declarator D1 seen in 9.3.4.6 [dcl.fct] is just f, and the derived-declarator-type-list is thus empty.
By contrast, the declarator (*fp)() -> int is parsed as the direct-declarator (*fp) followed by the parameter-declaration-clause, etc. In this case, D1 in 9.3.4.6 [dcl.fct] is (*fp) and the derived-declarator-type-list is “pointer to,” i.e., not empty.
My personal view is that there is no reason to forbid the (*fp)() -> int form, and that doing so is problematic. For example, this restriction would require users desiring the late-specified return type syntax to write function parameters as function types and rely on parameter type transformations rather than writing them as pointer-to-function types, as they will actually turn out to be:
void f(auto (*fp)() -> int); // ill-formed void f(auto fp() -> int); // OK (but icky)
It may be helpful in deciding whether to allow this form to consider the example of a function returning a pointer to a function. With the current restriction, only one of the three plausible forms is allowed:
auto (*f())() -> int; // Disallowed auto f() -> int (*)(); // Allowed auto f() -> auto (*)() -> int; // DisallowedSuggested resolution:
Delete the words “and the derived-declarator-type-list shall be empty” from 9.3.4.6 [dcl.fct] paragraph 2.
Add a new paragraph following 9.3 [dcl.decl] paragraph 4:
A ptr-operator shall not be applied, directly or indirectly, to a function declarator with a late-specified return type (9.3.4.6 [dcl.fct]).
Proposed resolution (June, 2008):
Change the grammar in 9.3 [dcl.decl] paragraph 4 as follows:
Change the grammar in 9.3.2 [dcl.name] paragraph 1 as follows:
Change 9.3.4.6 [dcl.fct] paragraph 2 as follows:
... T shall be the single type-specifier autoand the derived-declarator-type-list shall be empty. Then the type...
Change all occurrences of direct-new-declarator in 7.6.2.8 [expr.new] to noptr-new-declarator. These changes appear in the grammar in paragraph 1 and in the text of paragraphs 6-8, as follows:
...
new-declarator:
ptr-operator new-declaratoropt
direct-noptr-new-declarator
direct-noptr-new-declarator:
[ expression ]
...
direct-noptr-new-declarator [ constant-expression ]
When the allocated object is an array (that is, the
direct-noptr-new-declarator syntax is used or the new-type-id or type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array. [Note: both new int and new int[10] have type int* and the type of new int[i][10] is int (*)[10] —end note]Every constant-expression in a
direct-noptr-new-declarator shall be an integral constant expression (7.7 [expr.const]) and evaluate to a strictly positive value. The expression in adirect-noptr-new-declarator shall be of integral type, enumeration type, or a class type for which a single non-explicit conversion function to integral or enumeration type exists (11.4.8 [class.conv]). If the expression is of class type, the expression is converted by calling that conversion function, and the result of the conversion is used in place of the original expression. If the value of the expression is negative, the behavior is undefined. [Example: given the definition int n = 42, new float[n][5] is well-formed (because n is the expression of adirect-noptr-new-declarator), but new float[5][n] is ill-formed (because n is not a constant expression). If n is negative, the effect of new float[n][5] is undefined. —end example]When the value of the expression in a
direct-noptr-new-declarator is zero, the allocation function is called to allocate an array with no elements.