问题
Where in the standard are functions returning functions disallowed? I understand they are conceptually ridiculous, but it seems to me that the grammar would allow them. According to this webpage, a "noptr-declarator [is] any valid declarator" which would include the declarator of a function:
int f()();
Regarding the syntax.
It seems to me that the syntax, as spelled out in [dcl.decl], allows
int f(char)(double)
which could be interpreted as the function f
that takes a char
and returns a function with same signature as int g(double)
.
1 declarator:
2 ptr-declarator
3 noptr-declarator parameters-and-qualifiers trailing-return-type
4 ptr-declarator:
5 noptr-declarator
6 ptr-operator ptr-declarator
7 noptr-declarator:
8 declarator-id attribute-specifier-seq opt
9 noptr-declarator parameters-and-qualifiers
10 noptr-declarator [ constant-expression opt ] attribute-specifier-seq opt
11 ( ptr-declarator )
12 parameters-and-qualifiers:
13 ( parameter-declaration-clause ) cv-qualifier-seqAfter
Roughly speaking, after 1->2, 2=4, 4->6, 4->6 you should have ptr-operator ptr-operator ptr-operator Then, use 4->5, 5=7, 7->8 for the first declarator; use 4->5, 5=7, 7->9 for the second and third declarators.
回答1:
From [dcl.fct], pretty explicitly:
Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays of pointers to functions.
With C++11, you probably just want:
std::function<int()> f();
std::function<int(double)> f(char);
There is some confusion regarding the C++ grammar. The statement int f(char)(double);
can be parsed according to the grammar. Here is a parse tree:

Furthermore such a parse is even meaningful based on [dcl.fct]/1:
In a declaration
T D
whereD
has the form
D1
( parameter-declaration-clause ) cv-qualifier-seqopt
ref-qualifieroptexception-specificationoptattribute-specifier-seqopt
and the type of the contained declarator-id in the declarationT D1
is “derived-declarator-type-listT
”, the type of the declarator-id inD
is “derived-declarator-type-list function of (parameter-declaration-clause ) cv-qualifier-seqoptref-qualifieropt returningT
”.
In this example T == int
, D == f(char)(double)
, D1 == f(char)
. The type of the declarator-id in T D1
(int f(char)
) is "function of (char) returning int". So derived-declarator-type-list is "function of (char) returning". Thus, the type of f
would be read as "function of (char) returning function of (double) returning int."
It's ultimately much ado about nothing, as this is an explicitly disallowed declarator form. But not by the grammar.
回答2:
With C++11 (but not previous versions of C++) you can not only return C-like function pointers, but also C++ closures, notably with anonymous functions. See also std::function
The standard disallows (semantically, not syntactically - so it is not a question of grammar ; see Barry's answer for the citation) returning functions (and also disallow sizeof
on functions!) but permits to return function pointers.
BTW, I don't think that you could return entire functions. What would that mean? How would you implement that? Practically speaking, a function is some code block, and its name is (like for arrays) a pointer to the start of the function's machine code.
A nice trick might be to build (using mechanisms outside of the C++ standard) a function at runtime (and then handling its function pointer). Some external libraries might permit that: you could use a JIT library (e.g. asmjit, gccjit, LLVM ...) or simply generate C++ code, then compile and dlopen & dlsym it on POSIX systems, etc.
PS. You are probably right in understanding that the C++11 grammar (the EBNF rules in the standard) does not disallow returning functions. It is a semantic rule stated in plain English which disallows that (it is not any grammar rule). I mean that the EBNF alone would allow:
// semantically wrong... but perhaps not syntactically
typedef int sigfun_T(std::string);
sigfun_T foobar(int);
and it is for semantics reasons (not because of EBNF rules) that a compiler is rightly rejecting the above code. Practically speaking, the symbol table matters a lot to the C++ compiler (and it is not syntax or context-free grammar).
The sad fact about C++ is that (for legacy reasons) its grammar (alone) is very ambiguous. Hence C++11 is difficult to read (for humans), difficult to write (for developers), difficult to parse (for compilers), ....
回答3:
Actually in C one cannot pass or return function. Only a pointer/address of the function can be passed/returned, which conceptually is pretty close. To be honest, thanks to possiblity of ommiting &
and *
with function pointers one shouldn't really care if function or pointer is passed (unless it contains any static data). Here is simple function pointer declaration:
void (*foo)();
foo is pointer to function returning void and taking no arguments.
In C++ it is not that much different. One can still use C-style function pointers or new useful std::function
object for all callable creations. C++ also adds lambda expressions which are inline functions which work somehow similar to closures in functional languages. It allows you not to make all passed functions global.
And finally - returning function pointer or std::function
may seem ridiculous, but it really is not. For example, the state machine pattern is (in most cases) based on returning pointer to function handling next state or callable next state object.
回答4:
The formal grammar of C actually disallows returning functions but, one can always return a function pointer which, for all intents and purposes, seems like what you want to do:
int (*getFunc())(int, int) { … }
I am fixated in saying, the grammar, is a more fundamental explanation for the lack of support of such feature. The standard's rules are a latter concern.
If the grammar does not provide for a way to accomplish something, I don't think it matters what the semantics or the standard says for any given context-free language.
回答5:
Unless you are returning a pointer or reference to a function which is ok, the alternative is returning a copy of a function. Now, think about what a copy of a function looks like, acts like, behaves like. That, first of all would be an array of bytes, which isn't allowed either, and second of all those bytes would be the equivalence of a piece of code literally returning a piece of code....nearly all heuristic virus scanners would consider that a virus because there would also be no way to verify the viability of the code being returned by the runtime system or even at compile time. Even if you could return an array, how would you return a function? The primary issue with returning an array (which would be a copy on the stack) is that the size is not known and so there's no way to remove it from the stack, and the same dilemma exists for functions (where the array would be the machine language binary code). Also, if you did return a function in that fashion, how would you turn around and call that function?
To sum up, the notion of returning a function rather than a point to a function fails because the notion of that is a unknown size array of machine code placed (copied) onto the stack. It's not something the C or C++ was designed to allow, and with code there is now way to turn around and call that function, especially i you wanted to pass arguments.
I hope this makes sense
来源:https://stackoverflow.com/questions/31387238/c-function-returning-function