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 == intD == 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;
}