38

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.

Hector
  • 2,464
  • 3
  • 19
  • 34
  • C way - return void * and cast it to function :) C++ way - return reference or pointer to object that have some function (strategy pattern) – Nick Jul 13 '15 at 15:21
  • 25
    That's truly terrible advice. Even in C you can return a function pointer. In C++ you can use std::function or any callable object. – Puppy Jul 13 '15 at 15:26
  • Linux' `signal` function is a typical example of a function returning another function(-pointer), and I don't think that this is ridiculus. The only thing ridiculus is the syntax: `void (*signal(int signo, void (*func )(int)))(int);` – maja Jul 13 '15 at 15:29
  • 4
    @maja: That does not return a function. It returns a function pointer. – Lightness Races in Orbit Jul 13 '15 at 15:30
  • @maja: Right, well, now you're making the same mistake as Anzurio. The OP did not say that returning function pointers is ridiculous. At all. – Lightness Races in Orbit Jul 13 '15 at 15:32
  • @LightnessRacesinOrbit Damn. Read the question as if OP wants to return function pointers and not actual functions. – maja Jul 13 '15 at 15:36
  • 1
    You are wrong in thinking that C++ is mostly defined by a grammar. The grammar does not means a lot (and is known to be extremely ambiguous for C++; this is why coding C++ parsers is boringly difficult, and so is reading C++ code!) – Basile Starynkevitch Jul 13 '15 at 15:45
  • 2
    I finally downvoted the question, because it is mixing *grammar* and *language definition* which for C++ particularly (and sadly IMHO) is very different. This is why C++ is so difficult to read, difficult to learn, difficult to parse (all this because of *legacy* and *backward look&feel compatibility with C* reasons) – Basile Starynkevitch Jul 13 '15 at 16:12
  • @BasileStarynkevitch: *grammar* and *language definition* were shaken, not stirred. So, why is the mix bad? – Hector Jul 13 '15 at 16:56
  • 1
    You mention that the grammar would allow them, and you are right; it is not the grammar which forbids that. But I've understood your question as asking for some syntax rule forbidding it (and there are none, since it is a semantic issue) – Basile Starynkevitch Jul 13 '15 at 17:02
  • @BasileStarynkevitch The question is "Where in the standard are functions returning functions disallowed?" It's not qualified by asking for a specific syntax rule. – Barry Jul 13 '15 at 17:09
  • @Barry: the next sentence in the question is ending "it seems to me that the grammar would allow them", so can be understood (at least by the non-native English speaker that I am) as why the grammar is forbidding that... – Basile Starynkevitch Jul 13 '15 at 18:32
  • 5
    There is nothing conceptually ridiculous about functions returning functions. It's done all the time in other languages. it is even done in C++ in the form of functions returning closures. – Theodore Norvell Jul 13 '15 at 20:09
  • Possible duplicate of [Function returning a lambda expression](https://stackoverflow.com/questions/4726768/function-returning-a-lambda-expression) – Colonel Panic Apr 09 '19 at 15:46

8 Answers8

58

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:

grammar

Furthermore such a parse is even meaningful based on [dcl.fct]/1:

In a declaration T D where D has the form

    D1 ( parameter-declaration-clause ) cv-qualifier-seqopt
        ref-qualifieropt exception-specificationopt attribute-specifier-seqopt

and the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T”, the type of the declarator-id in D is “derived-declarator-type-list function of (parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt returning T”.

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.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    Notice that it is not a *grammar* thing. The C++ grammar (in quasi EBNF notation) probably allows returning functions. The semantics forbid it. – Basile Starynkevitch Jul 13 '15 at 15:50
  • The standard is over 1000 pages. It is easy to overlook stuff. In this case, that is paragraph 10 ... too way down ... – Hector Jul 13 '15 at 15:53
  • 3
    @Hector That's why we have PDFs with bookmarks. Jump to the **Functions** section (8.3.5), then search for "return" – Barry Jul 13 '15 at 16:08
  • 2
    @Barry: no need to be condescending. I did search in 8.4 then the first two pages of 8.3.5. By that point, I thought I did not understand something. – Hector Jul 13 '15 at 16:16
  • 6
    @Hector I wasn't intending to be condescending. I thought you were reading the paper version and was suggesting a more convenient alternative. – Barry Jul 13 '15 at 16:29
  • The parsing graph is very nice and I am curious how you generate it. What tool is used to generate such graph, it would be very useful for learning! Can you share some information here? – Nick Huang Oct 19 '21 at 13:26
7

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), ....

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 2
    "The standard disallow[s] returning functions" does not answer the question "which part of the standard disallow[s] returning functions". – Lightness Races in Orbit Jul 13 '15 at 15:31
  • 1
    _"BTW, I don't think that you could return entire functions. What would that mean? How would you implement that."_ Right, the OP said that in the question. Nobody can read today :( – Lightness Races in Orbit Jul 13 '15 at 15:33
  • Actually, with a jit library, you could return a function; or at least a block of memory containing one. – RamblingMad Jul 13 '15 at 15:41
  • @CofeeandCode: technically, a JIT library would return a function pointer and build a function code in the address space. – Basile Starynkevitch Jul 13 '15 at 15:55
  • @BasileStarynkevitch you could write a `struct func{unsigned char[1024];};` and return that, then you would be returning the whole function. – RamblingMad Jul 13 '15 at 16:02
  • But that usually won't work. And pedantically, you are then returning a `struct` not a function. – Basile Starynkevitch Jul 13 '15 at 16:04
  • @LightnessRacesinOrbit: Just being the devil's advocate here. If we return a processor instruction (which might fit in a register), we might be returning a function. – Hector Jul 13 '15 at 16:07
  • Most processors are unable to execute an instruction in a register. IIRC, IBM/360 had an "Execute" machine instruction, but even that needed a memory address.... – Basile Starynkevitch Jul 13 '15 at 16:09
  • @Hector: Not really. The type system exists! – Lightness Races in Orbit Jul 13 '15 at 17:49
  • 1
    @LightnessRacesinOrbit: I'll advocate for the devil again. The interpretation of what is being held in a register is not part of C++. It could be a function. I was addressing the comments about JIT libraries returning pointers to functions instead of functions. – Hector Jul 13 '15 at 18:45
  • @Hector: The question is about C++. What you do with some registers in some physical implementation has nothing to do with it. :) – Lightness Races in Orbit Jul 13 '15 at 18:56
  • @LightnessRacesinOrbit Imagine returning a variable-size byte array that happens to contain machine code. (The variable-size array itself; not a pointer to it). Note that in C and C++ all variables have fixed sizes, so you can't return a variable-size object, so you can't return a function. (But you can return a pointer to one) – user253751 Jul 14 '15 at 02:02
  • @immibis: And even if you could, it would still not be a function. It would be an array. – Lightness Races in Orbit Jul 14 '15 at 09:45
  • @LightnessRacesinOrbit **If** the language allowed you to return functions, that is what returning a function would do - it would return a function. Functions happen to be represented by variable-length byte arrays on all machines I'm aware of, but for the language's purposes, it would be a function not an array. – user253751 Jul 14 '15 at 09:49
  • @immibis: Right, well that's not what you said a moment ago. :) Again, the type system exists and I deliberately do not ignore it. Not really fussed about implementation details as that is not what we are talking about here. – Lightness Races in Orbit Jul 14 '15 at 09:56
  • @LightnessRacesinOrbit You asked what it would mean to return a function, I answered. Think of the difference between returning a pointer to an array, and returning the array itself - that's the difference between returning a pointer to a function, and returning the function itself. Hypothetically. – user253751 Jul 14 '15 at 10:20
  • @immibis: I didn't ask anything! – Lightness Races in Orbit Jul 14 '15 at 10:21
5
using namespace std;

auto hello()
{
    char name[] = "asdf";
    return [&]() -> void
    {
        printf("%s\n", name);
    };
}

int main()
{
    hello()();
    auto r = hello();
    r();
    return 0;
}
januw a
  • 2,056
  • 5
  • 18
  • 39
  • 3
    While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Dharman Aug 27 '20 at 22:02
  • Sorry, I am a c++ rookie, I only know that writing code like this can solve the problem, but I don’t understand how this code works – januw a Aug 28 '20 at 01:19
  • The `auto` is probably deduced to be a function pointer, not a function – palapapa May 21 '23 at 12:15
0

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.

Anzurio
  • 16,780
  • 3
  • 39
  • 49
  • How do you find useful something that is impossible? – Lightness Races in Orbit Jul 13 '15 at 15:24
  • 1
    @LightnessRacesinOrbit I meant something like "returning functions by means of function pointers". – Anzurio Jul 13 '15 at 15:29
  • Well, that's not what the OP said. – Lightness Races in Orbit Jul 13 '15 at 15:31
  • 3
    "The standard disallow[s] returning functions" does not answer the question "which part of the standard disallow[s] returning functions". – Lightness Races in Orbit Jul 13 '15 at 15:33
  • @LightnessRacesinOrbit *sigh* Since it is so important to you (don't want to speculate why), I am removing that part of my answer. I reckon my actual answer may not really addresses the question; I am just trying to be helpful and not a self-righteous individual. – Anzurio Jul 13 '15 at 15:36
  • @Anzurio I don't think you understand LRiO's comment. What OP meant by "ridiculous" was returning functions as a value. You saying you find it useful doesn't make sense, since that isn't even legal C or C++ code. You're saying returning functions by pointer/reference/functor is useful - that is undoubtly true, but also sort of irrelevant to the question. – Barry Jul 13 '15 at 15:41
  • @Anzurio: Yes it is terrible that the quality of the content on this website is important to me – Lightness Races in Orbit Jul 13 '15 at 15:43
  • That part with my personal opinion was removed. I have no idea what else do you want? From my POV, the question is flawed because it's not the standard's "fault". The grammar does not permit returning functions. – Anzurio Jul 13 '15 at 15:46
  • It is not the grammar which disallow returning functions. It is the semantics (and unfortunately, most of C++11 semantics is described *informally* in technical English) – Basile Starynkevitch Jul 13 '15 at 15:48
  • @BasileStarynkevitch do you mind pointing me to the construct and/or path that allows it? I'd really like to know. – Anzurio Jul 13 '15 at 15:50
  • @BasileStarynkevitch I sustain is a grammar issue because it will be the pushdown automaton which will reject a program that "tries" to return a function. – Anzurio Jul 13 '15 at 15:56
  • 1
    I edited my answer to improve it. The codechunk starting with `typedef int sigfun_T(std::string);` is legal C++ *syntax* but it has no *meaning* – Basile Starynkevitch Jul 13 '15 at 16:01
  • 1
    I downvoted, because returning a function is forbidden by something which is *not the grammar* (but the "semantics"). – Basile Starynkevitch Jul 13 '15 at 16:08
  • 1
    I posted a parse tree to illustrate that the grammar does allow this. – Barry Jul 14 '15 at 04:14
0

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.

bartop
  • 9,971
  • 1
  • 23
  • 54
0

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

ydobonebi
  • 240
  • 2
  • 11
0

in kinda sense,function_pointer is funciton its self,
and "trailing return type" is a good and hiding thing in c++11,i will rather write like this:

#include<iostream>



auto return0(void)->int
{return 0;}
auto returnf(void)->decltype(&return0)
{return &return0;}



/*Edit: or...
auto returnf(void)->auto (*)(void)->int
{return &return0;}
//that star means function pointer
*/




auto main(void)->int
{
    std::cout<<returnf()();
    return 0;
}

(if type unmatch,try apply address operator "&")
look,so much of sense.

but down side of this is that "auto" thing in head of function,
that`s non-removable and no type could match it (even lambda could match template type std::function<>) but if you wish,macro could do magic(sometime curse) to you

#define func auto
AiDSl
  • 25
  • 6
0

You can still do that but in order to do it you need to set the return type like this std::function<return type(parameters)>. To call the function simply just do what you would normally do. Example:

std::function<void()> return_function {
    std::function<void()> myFunction();
    return myFunction
}