C++函数返回函数
C++ function returning function
标准中哪些地方不允许函数返回函数?我知道它们在概念上是荒谬的,但在我看来语法允许它们。根据此网页,“noptr-declarator [is] any valid declarator”将包含函数声明符:
int f()();
关于语法。
在我看来,[dcl.decl] 中阐明的语法允许
int f(char)(double)
可以解释为函数 f
需要一个 char
和 returns 具有与 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
粗略地说,经过
1->2, 2=4, 4->6, 4->6
你应该有
ptr-运算符 ptr-运算符 ptr-运算符
然后,使用 4->5, 5=7, 7->8 作为第一个声明符;对第二个和第三个声明符使用 4->5, 5=7, 7->9。
C 的正式语法实际上不允许 returning 函数,但是,人们总是可以 return 一个函数指针,就所有意图和目的而言,它看起来就像你想做的那样:
int (*getFunc())(int, int) { … }
我固执地说,语法,是对这种功能缺乏支持的更根本的解释。标准的规则是后一个问题。
如果语法没有提供完成某事的方法,我认为对于任何给定的上下文无关语言,语义或标准所说的内容并不重要。
和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
标准不允许(语义上,语法上不允许 - 所以它不是 grammar 的问题;参见 的引文)returning functions (并且还禁止 sizeof
函数!)但允许 return 函数指针 .
顺便说一句,我不认为你可以 return 整个函数。那是什么意思?你将如何实施?实际上,一个函数是一些代码块,它的名字(就像数组一样)是一个指向函数机器码开头的指针。
一个不错的技巧可能是在运行时构建(使用 C++ 标准之外的机制)一个函数(然后处理它的函数指针)。某些外部库可能允许:您可以使用 JIT 库(例如 asmjit, gccjit, LLVM ...) or simply generate C++ code, then compile and dlopen & dlsym 它在 POSIX 系统等
PS。您可能正确地理解了 C++11 语法(标准中的 EBNF 规则)不禁止 returning 函数。这是一个语义规则,用简单的英语陈述,不允许这样做(不是任何语法规则)。我的意思是仅 EBNF 就允许:
// semantically wrong... but perhaps not syntactically
typedef int sigfun_T(std::string);
sigfun_T foobar(int);
它是因为 semantics reasons (not because of EBNF rules) that a compiler is rightly rejecting the above code. Practically speaking, the symbol table 对 C++ 编译器很重要(它是 不是 语法或上下文无关语法)。
关于 C++ 的可悲事实是(由于遗留原因)它的语法(单独)非常模棱两可。因此,C++11 难以阅读(对人类而言),难以编写(对开发人员而言),难以解析(对编译器而言),....
来自 [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.
对于 C++11,您可能只需要:
std::function<int()> f();
std::function<int(double)> f(char);
C++ 语法有些混乱。语句int f(char)(double);
可以按语法解析。这是一个解析树:
此外,基于 [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
”.
在此示例中 T == int
、D == f(char)(double)
、D1 == f(char)
。 T D1
(int f(char)
) 中 declarator-id 的类型是 "function of (char) returning int"。所以 derived-declarator-type-list 是 "function of (char) returning"。因此,f
的类型将被读作 "function of (char) returning function of (double) returning int."
这最终是无事生非,因为这是一种明确不允许的声明形式。但不是语法。
实际上在 C 中不能传递或 return 函数。只有一个pointer/address的函数可以是passed/returned,这在概念上已经很接近了。老实说,多亏了函数指针省略 &
和 *
的可能性,人们不应该真正关心函数或指针是否被传递(除非它包含任何静态数据)。这是简单的函数指针声明:
void (*foo)();
foo 是指向函数的指针 return 无效且不带参数。
在 C++ 中,差别不大。对于所有可调用的创建,仍然可以使用 C 风格的函数指针或新的有用的 std::function
对象。 C++ 还添加了 lambda expressions ,它们是内联函数,在某种程度上类似于函数式语言中的闭包。它允许您不将所有传递的函数设为全局。
最后 - returning 函数指针或 std::function
可能看起来很荒谬,但事实并非如此。例如,状态机模式(在大多数情况下)基于 return 指向函数处理下一个状态或可调用下一个状态对象的指针。
除非您return指向一个函数的指针或引用是可以的,否则另一种方法是return一个函数的副本。现在,想想一个函数的副本看起来像什么,行为像什么,行为像什么。那,首先是一个字节数组,这也是不允许的,而所有这些字节中的第二个将是一段代码的等价物 returning 一段代码....几乎所有启发式病毒扫描程序都会认为这是一种病毒,因为也没有办法验证运行时系统甚至在编译时 return 编辑的代码的可行性。即使你可以 return 一个数组,你如何 return 一个函数? returning 数组(这将是堆栈上的副本)的主要问题是大小未知,因此无法将其从堆栈中删除,并且函数存在相同的困境(其中该数组将是机器语言二进制代码)。此外,如果您以那种方式 return 执行一个函数,您将如何转身调用该函数?
总而言之,returning 一个函数而不是指向一个函数的概念失败了,因为这个概念是一个未知大小的机器代码数组放置(复制)到堆栈上。这不是 C 或 C++ 旨在允许的东西,现在有了代码,可以转身调用该函数,尤其是当你想传递参数时。
我希望这是有道理的
在某种意义上,function_pointer 是其自身的功能,
"trailing return type" 在 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;
}
(如果类型不匹配,尝试应用地址运算符“&”)
看,很有道理。
但不利的一面是 "auto" 函数头部的东西,
那是不可移动的,没有类型可以匹配它(甚至 lambda 可以匹配模板类型 std::function<>)
但如果你愿意,宏可以对你施展魔法(有时是诅咒)
#define func auto
using namespace std;
auto hello()
{
char name[] = "asdf";
return [&]() -> void
{
printf("%s\n", name);
};
}
int main()
{
hello()();
auto r = hello();
r();
return 0;
}
标准中哪些地方不允许函数返回函数?我知道它们在概念上是荒谬的,但在我看来语法允许它们。根据此网页,“noptr-declarator [is] any valid declarator”将包含函数声明符:
int f()();
关于语法。
在我看来,[dcl.decl] 中阐明的语法允许
int f(char)(double)
可以解释为函数 f
需要一个 char
和 returns 具有与 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
粗略地说,经过 1->2, 2=4, 4->6, 4->6 你应该有 ptr-运算符 ptr-运算符 ptr-运算符 然后,使用 4->5, 5=7, 7->8 作为第一个声明符;对第二个和第三个声明符使用 4->5, 5=7, 7->9。
C 的正式语法实际上不允许 returning 函数,但是,人们总是可以 return 一个函数指针,就所有意图和目的而言,它看起来就像你想做的那样:
int (*getFunc())(int, int) { … }
我固执地说,语法,是对这种功能缺乏支持的更根本的解释。标准的规则是后一个问题。
如果语法没有提供完成某事的方法,我认为对于任何给定的上下文无关语言,语义或标准所说的内容并不重要。
和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
标准不允许(语义上,语法上不允许 - 所以它不是 grammar 的问题;参见 sizeof
函数!)但允许 return 函数指针 .
顺便说一句,我不认为你可以 return 整个函数。那是什么意思?你将如何实施?实际上,一个函数是一些代码块,它的名字(就像数组一样)是一个指向函数机器码开头的指针。
一个不错的技巧可能是在运行时构建(使用 C++ 标准之外的机制)一个函数(然后处理它的函数指针)。某些外部库可能允许:您可以使用 JIT 库(例如 asmjit, gccjit, LLVM ...) or simply generate C++ code, then compile and dlopen & dlsym 它在 POSIX 系统等
PS。您可能正确地理解了 C++11 语法(标准中的 EBNF 规则)不禁止 returning 函数。这是一个语义规则,用简单的英语陈述,不允许这样做(不是任何语法规则)。我的意思是仅 EBNF 就允许:
// semantically wrong... but perhaps not syntactically
typedef int sigfun_T(std::string);
sigfun_T foobar(int);
它是因为 semantics reasons (not because of EBNF rules) that a compiler is rightly rejecting the above code. Practically speaking, the symbol table 对 C++ 编译器很重要(它是 不是 语法或上下文无关语法)。
关于 C++ 的可悲事实是(由于遗留原因)它的语法(单独)非常模棱两可。因此,C++11 难以阅读(对人类而言),难以编写(对开发人员而言),难以解析(对编译器而言),....
来自 [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.
对于 C++11,您可能只需要:
std::function<int()> f();
std::function<int(double)> f(char);
C++ 语法有些混乱。语句int f(char)(double);
可以按语法解析。这是一个解析树:
此外,基于 [dcl.fct]/1:
这样的解析甚至是有意义的In a declaration
T D
whereD
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 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-seqopt ref-qualifieropt returningT
”.
在此示例中 T == int
、D == f(char)(double)
、D1 == f(char)
。 T D1
(int f(char)
) 中 declarator-id 的类型是 "function of (char) returning int"。所以 derived-declarator-type-list 是 "function of (char) returning"。因此,f
的类型将被读作 "function of (char) returning function of (double) returning int."
这最终是无事生非,因为这是一种明确不允许的声明形式。但不是语法。
实际上在 C 中不能传递或 return 函数。只有一个pointer/address的函数可以是passed/returned,这在概念上已经很接近了。老实说,多亏了函数指针省略 &
和 *
的可能性,人们不应该真正关心函数或指针是否被传递(除非它包含任何静态数据)。这是简单的函数指针声明:
void (*foo)();
foo 是指向函数的指针 return 无效且不带参数。
在 C++ 中,差别不大。对于所有可调用的创建,仍然可以使用 C 风格的函数指针或新的有用的 std::function
对象。 C++ 还添加了 lambda expressions ,它们是内联函数,在某种程度上类似于函数式语言中的闭包。它允许您不将所有传递的函数设为全局。
最后 - returning 函数指针或 std::function
可能看起来很荒谬,但事实并非如此。例如,状态机模式(在大多数情况下)基于 return 指向函数处理下一个状态或可调用下一个状态对象的指针。
除非您return指向一个函数的指针或引用是可以的,否则另一种方法是return一个函数的副本。现在,想想一个函数的副本看起来像什么,行为像什么,行为像什么。那,首先是一个字节数组,这也是不允许的,而所有这些字节中的第二个将是一段代码的等价物 returning 一段代码....几乎所有启发式病毒扫描程序都会认为这是一种病毒,因为也没有办法验证运行时系统甚至在编译时 return 编辑的代码的可行性。即使你可以 return 一个数组,你如何 return 一个函数? returning 数组(这将是堆栈上的副本)的主要问题是大小未知,因此无法将其从堆栈中删除,并且函数存在相同的困境(其中该数组将是机器语言二进制代码)。此外,如果您以那种方式 return 执行一个函数,您将如何转身调用该函数?
总而言之,returning 一个函数而不是指向一个函数的概念失败了,因为这个概念是一个未知大小的机器代码数组放置(复制)到堆栈上。这不是 C 或 C++ 旨在允许的东西,现在有了代码,可以转身调用该函数,尤其是当你想传递参数时。
我希望这是有道理的
在某种意义上,function_pointer 是其自身的功能,
"trailing return type" 在 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;
}
(如果类型不匹配,尝试应用地址运算符“&”)
看,很有道理。
但不利的一面是 "auto" 函数头部的东西,
那是不可移动的,没有类型可以匹配它(甚至 lambda 可以匹配模板类型 std::function<>)
但如果你愿意,宏可以对你施展魔法(有时是诅咒)
#define func auto
using namespace std;
auto hello()
{
char name[] = "asdf";
return [&]() -> void
{
printf("%s\n", name);
};
}
int main()
{
hello()();
auto r = hello();
r();
return 0;
}