标准中哪些函数不允许返回函数?我知道它们在概念上是荒谬的,但在我看来,语法会允许它们。根据这个网页," noptr-declarator [is] any valid declarator"其中包括函数的声明者:
#!/usr/local/bin/perl
use strict;
use warnings;
my %M_hash;
my %F_hash;
open (my $input, "<", 'ssbn1898.txt');
while ( <$input> ) {
chomp;
my ( $name, $id ) = split ( /,/ );
if ( $id eq "M" ) {
push ( %M_hash, $name );
}
else {
push ( %F_hash, $name );
}
}
close ( $input );
print 'M: ' . join("\t", %M_hash) . "\n";
print 'F: ' . join("\t", %F_hash) . "\n";
关于语法。
在我看来,[dcl.decl]中详细说明的语法允许
int f()();
可以解释为函数 int f(char)(double)
,它接受 f
并返回一个具有相同签名的函数 char
。
int g(double)
粗略地讲,之后 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。
答案 0 :(得分:54)
来自[dcl.fct],非常明确地说:
函数不应具有类型数组或函数的返回类型,尽管它们的返回类型可能为 键入指针或对此类事物的引用。虽然可以有数组,但不应有任何函数数组 指向函数的指针。
使用C ++ 11,您可能只想要:
std::function<int()> f();
std::function<int(double)> f(char);
关于C ++语法存在一些混淆。可以根据语法解析语句int f(char)(double);
。这是一个解析树:
此外,基于[dcl.fct] / 1:
,这样的解析甚至是有意义的在声明
T D
中,D
的格式为D1
( parameter-declaration-clause ) cv-qualifier-seq opt
ref-qualifier opt exception-specification opt attribute-specifier-seq 选择子>
并且声明T D1
中包含的 declarator-id 的类型是“ derived-declarator-type-listT
”,D
中 declarator-id 的类型是( parameter-declaration-clause 的 derived-declarator-type-list 函数) cv-qualifier-seq opt ref-qualifier opt 返回T
“。
在此示例中T == int
,D == f(char)(double)
,D1 == f(char)
。 T D1
(int f(char)
)中 declarator-id 的类型是“(char)return int”的函数。所以 derived-declarator-type-list 是“(char)返回的函数”。因此,f
的类型将被读作“(char)返回函数的函数(double)返回int。”
这最终无关紧要,因为这是一个明确禁止的声明者形式。但不是语法。
答案 1 :(得分:7)
使用C++11(但不是以前的C ++版本),您不仅可以返回类C函数指针,还可以返回C ++ closures,尤其是anonymous functions。另请参阅std::function
标准不允许( 语义 ,而不是语法 - 所以 > ;请参阅Barry's answer以获取引文)返回函数(并且还禁止sizeof
函数!)但允许返回函数指针
BTW,我认为你不能归还整个功能。那是什么意思?你会如何实现?实际上,函数是一些代码块,它的名称(就像数组一样)是指向函数机器代码开头的指针。
一个很好的技巧可能是在运行时构建(使用C ++标准的外部机制)函数(然后处理它的函数指针)。一些外部库可能允许:您可以使用JIT库(例如asmjit,gccjit,LLVM ...)或者只是生成C ++代码,然后编译并dlopen &安培; dlsym它在POSIX系统上等等。
PS。你可能正确地理解C ++ 11 语法(标准中的EBNF规则)不允许返回函数。这是一个用简单的英语表达的语义规则,它不允许(不任何语法规则)。我的意思是单独的EBNF会允许:
// semantically wrong... but perhaps not syntactically
typedef int sigfun_T(std::string);
sigfun_T foobar(int);
由于semantics原因(不是因为EBNF规则),编译器正确地拒绝上述代码。实际上,symbol table对C ++编译器很重要(并且不是语法或无上下文语法)。
关于C ++的可悲事实是(由于遗留原因)它的语法(单独)非常模糊。因此,C ++ 11难以阅读(对于人类而言),难以编写(对于开发人员而言),难以解析(对于编译器而言),....
答案 2 :(得分:0)
C的形式语法实际上不允许返回函数,但是,总是可以返回一个函数指针,出于所有意图和目的,它似乎就像你想要做的那样:
int (*getFunc())(int, int) { … }
我很着迷说,语法是对这种功能缺乏支持的更基本的解释。标准的规则是后一个问题。
如果语法没有提供某种方法来完成某些事情,那么对于任何给定的无上下文语言,我认为语义或标准所说的并不重要。
答案 3 :(得分:0)
除非您返回一个指针或对函数的引用,否则替代方法是返回函数的副本。现在,考虑一下函数的副本是什么样的,行为就像,表现得像。首先,这将是一个字节数组,也是不允许的,其中第二个字节将是一段代码的等价物,字面上返回一段代码....几乎所有的启发式病毒扫描程序会认为是病毒,因为也无法验证运行时系统返回的代码的可行性,甚至无法在编译时验证。即使你可以返回一个数组,你会如何返回一个函数?返回数组(可能是堆栈上的副本)的主要问题是大小未知,因此无法将其从堆栈中删除,并且函数存在同样的困境(其中数组将是机器语言二进制代码)。另外,如果你确实以这种方式返回一个函数,你会如何转身并调用该函数?
总而言之,将函数而不是函数返回函数的概念失败了,因为它的概念是放置(复制)到堆栈上的未知大小的机器代码数组。它不是C或C ++设计允许的东西,而且现在有了转向并调用该函数的方法,特别是我想要传递参数。
我希望这是有道理的
答案 4 :(得分:0)
从某种意义上说,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;
}
(如果类型不匹配,请尝试使用地址运算符“&”)
看,很有道理。
但缺点是功能开头的“自动”内容,
那是不可移动的,没有类型可以匹配它(即使lambda也可以匹配模板类型std :: function <>)
但是如果您愿意,宏可以为您做魔术(有时是诅咒)
#define func auto
答案 5 :(得分:0)
using namespace std;
auto hello()
{
char name[] = "asdf";
return [&]() -> void
{
printf("%s\n", name);
};
}
int main()
{
hello()();
auto r = hello();
r();
return 0;
}
答案 6 :(得分:-1)
实际上在C中一个人无法通过或返回功能。只能传递/返回函数的指针/地址,这在概念上非常接近。老实说,由于可能会遗漏&
和*
函数指针,因此不应该关注函数或指针是否传递(除非它包含任何静态数据)。这是简单的函数指针声明:
void (*foo)();
foo是函数返回void并且不带参数的指针。
在C ++中它并没有太大的不同。对于所有可调用的创建,仍然可以使用C风格的函数指针或新的有用的std::function
对象。 C ++还添加了lambda expressions,它们是内联函数,它们在某种程度上类似于函数式语言中的闭包。它允许您不要将所有传递的函数全局化。
最后 - 返回函数指针或std::function
可能看起来很荒谬,但实际上并非如此。例如,状态机模式(在大多数情况下)基于返回指向函数处理下一状态或可调用的下一状态对象的指针。