C++函数返回函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31387238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ function returning function
提问by Hector
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:
标准中的哪些地方不允许返回函数?我知道它们在概念上是荒谬的,但在我看来,语法允许它们。根据此网页,“ noptr-declarator [is] any valid declarator”将包括函数的声明符:
int f()();
Regarding the syntax.
关于语法。
It seems to me that the syntax, as spelled out in [dcl.decl], allows
在我看来,[dcl.decl] 中阐明的语法允许
int f(char)(double)
which could be interpreted as the functionf
that takes achar
and returns a function with same signature asint g(double)
.
这可以解释为功能f
,需要一个char
并返回相同的签名功能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->2, 2=4, 4->6, 4->6 之后你应该有 ptr-operator ptr-operator ptr-operator 然后,使用 4->5, 5=7, 7->8对于第一个声明符;对第二个和第三个声明符使用 4->5, 5=7, 7->9。
回答by Barry
From [dcl.fct], pretty explicitly:
来自 [dcl.fct],非常明确:
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:
使用 C++11,您可能只想要:
std::function<int()> f();
std::function<int(double)> f(char);
There is some confusion regarding the C++ grammar. The statement int f(char)(double);
canbe parsed according to the grammar. Here is a parse tree:
关于 C++ 语法有一些混淆。语句int f(char)(double);
可以根据语法进行解析。这是一个解析树:
Furthermore such a parse is even meaningful based on [dcl.fct]/1:
此外,基于 [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-idin the declarationT D1
is “derived-declarator-type-listT
”, the type of the declarator-idinD
is “derived-declarator-type-listfunction of (parameter-declaration-clause) cv-qualifier-seqoptref-qualifieroptreturningT
”.
在声明
T D
,其中D
具有形式
D1
(参数声明子句)CV-限定符-SEQ选择
REF-限定符选择异常规范选择属性说明符-SEQ选择
和所含的类型说明符-ID中的声明T D1
是“ derived-说明符类型列表T
”,该类型说明符-ID中D
是‘衍生的说明符类型列表的(功能参数声明子句)CV-限定符-SEQ选择REF-限定符选择返回T
’。
In this example T == int
, D == f(char)(double)
, D1 == f(char)
. The type of the declarator-idin T D1
(int f(char)
) is "function of (char) returning int". So derived-declarator-type-listis "function of (char) returning". Thus, the type of f
would be read as "function of (char) returning function of (double) returning int."
在这个例子T == int
中D == f(char)(double)
,,D1 == f(char)
。的类型的说明符-ID中T D1
(int f(char)
)是“(字符)返回int的功能”。所以派生声明符类型列表是“(字符)返回的函数”。因此,类型f
将被读作“(char) 返回函数的(double) 返回int 的函数”。
It's ultimately much ado about nothing, as this is an explicitly disallowed declarator form. But not by the grammar.
它最终无所事事,因为这是一种明确不允许的声明符形式。但不是按语法。
回答by Basile Starynkevitch
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
使用C++11(但不是 C++ 的早期版本),您不仅可以返回类似 C 的函数指针,还可以返回 C++闭包,尤其是匿名函数。另见std::function
The standard disallows (semantically, not syntactically - so it is nota question of grammar; see Barry's answerfor the citation) returning functions(and also disallow sizeof
on functions!) but permits to return function pointers.
标准不允许(语义上,而不是句法上 - 所以这不是语法问题;请参阅巴里的引用答案)返回函数(并且还禁止sizeof
函数!)但允许返回函数指针。
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 outsideof 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& dlsymit on POSIX systems, etc.
一个不错的技巧可能是在运行时构建(使用C++ 标准之外的机制)一个函数(然后处理它的函数指针)。一些外部库可能允许:您可以使用 JIT 库(例如asmjit、gccjit、LLVM...)或简单地生成 C++ 代码,然后在 POSIX 系统上编译和dlopen和dlsym等。
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 rulestated in plain English which disallows that (it is notany grammar rule). I mean that the EBNF alone would allow:
附注。您可能正确理解 C++11语法(标准中的 EBNF 规则)不允许返回函数。这是一个用简单英语陈述的语义规则,不允许这样做(它不是任何语法规则)。我的意思是仅 EBNF 就允许:
// semantically wrong... but perhaps not syntactically
typedef int sigfun_T(std::string);
sigfun_T foobar(int);
and it is for semanticsreasons (not because of EBNF rules) that a compiler is rightly rejecting the above code. Practically speaking, the symbol tablematters a lot to the C++ compiler (and it is notsyntax or context-free grammar).
并且出于语义原因(不是因为 EBNF 规则),编译器正确地拒绝了上述代码。实际上,符号表对 C++ 编译器很重要(它不是语法或上下文无关语法)。
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), ....
关于 C++ 的可悲事实是(由于遗留原因)它的语法(单独)非常模糊。因此,C++11 难以阅读(对于人类),难以编写(对于开发人员),难以解析(对于编译器),......
回答by Anzurio
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:
C 的正式语法实际上不允许返回函数,但是,您总是可以返回一个函数指针,出于所有意图和目的,它似乎是您想要做的:
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.
如果语法没有提供完成某事的方法,我认为对于任何给定的上下文无关语言,语义或标准所说的内容并不重要。
回答by bartop
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:
实际上在 C 中一个不能传递或返回函数。只能传递/返回函数的指针/地址,这在概念上非常接近。老实说,由于可以省略&
和*
使用函数指针,人们不应该真正关心是否传递了函数或指针(除非它包含任何静态数据)。这是简单的函数指针声明:
void (*foo)();
foo is pointer to function returning void and taking no arguments.
foo 是指向返回 void 且不带参数的函数的指针。
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 expressionswhich are inline functions which work somehow similar to closures in functional languages. It allows you not to make all passed functions global.
在 C++ 中,它并没有太大的不同。std::function
对于所有可调用的创建,仍然可以使用 C 风格的函数指针或新的有用对象。C++ 还添加了lambda 表达式,它们是内联函数,其工作方式类似于函数式语言中的闭包。它允许您不将所有传递的函数设为全局。
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.
最后 - 返回函数指针或std::function
看起来很荒谬,但事实并非如此。例如,状态机模式(在大多数情况下)基于返回指向处理下一状态或可调用下一状态对象的函数的指针。
回答by ydobonebi
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.
总而言之,返回函数而不是指向函数的点的概念失败了,因为该概念是放置(复制)到堆栈上的未知大小的机器代码数组。这不是 C 或 C++ 旨在允许的东西,现在有了代码可以转身并调用该函数,特别是我想传递参数。
I hope this makes sense
我希望这是有道理的
回答by AiDSl
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:
从某种意义上说,function_pointer 本身就是函数,
而“尾随返回类型”在 c++11 中是一个很好的隐藏的东西,我宁愿这样写:
#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
但
不利的一面是函数头部的“自动”东西,它是不可移动的,没有类型可以匹配它(即使 lambda 也可以匹配模板类型 std::function<>)但如果你愿意,宏可以做魔法(有时诅咒)给你
#define func auto