C++函数返回函数

Hec*_*tor 29 c++ standards language-lawyer c++11

标准中哪些函数不允许返回函数?我知道它们在概念上是荒谬的,但在我看来,语法会允许它们.根据这个网页," noptr-declarator [是]任何有效的声明符 ",它将包含一个函数的声明:

int f()();
Run Code Online (Sandbox Code Playgroud)

关于语法.

在我看来,[dcl.decl]中拼写的语法允许

int f(char)(double)
Run Code Online (Sandbox Code Playgroud)

这可以解释为功能 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
Run Code Online (Sandbox Code Playgroud)

粗略地说,在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.

Bar*_*rry 54

来自[dcl.fct],相当明确:

函数不应具有类型数组或函数的返回类型,尽管它们可能具有类型指针的返回类型或对此类事物的引用.虽然可以有函数指针数组,但是不应该有函数数组.

使用C++ 11,您可能只需要:

std::function<int()> f();
std::function<int(double)> f(char);
Run Code Online (Sandbox Code Playgroud)

关于C++语法存在一些混淆.int f(char)(double); 可以根据语法解析语句.这是一个解析树:

语法

此外,基于[dcl.fct]/1,这样的解析甚至是有意义的:

在声明T D,其中D具有形式
    D1(参数声明子句)CV-限定符-SEQ 选择
        REF-限定符选择 异常规范选择 属性说明符-SEQ 选择
和所含的类型说明符-ID中的声明T D1是" derived-说明符类型列表 T ",该类型说明符-IDD是' 衍生的说明符类型列表的(功能参数声明子句)CV-限定符-SEQ 选择 REF-限定符选择返回T’.

在这个例子T == intD == f(char)(double),D1 == f(char).的类型的说明符-IDT D1(int f(char))是"(字符)返回int的功能".所以derived-declarator-type-list是"(char)返回的函数".因此,类型f将被读作"(char)返回函数(double)返回int的函数".

它最终无关紧要,因为这是一个明确禁止的声明者形式.但不是语法.

  • @Hector我不打算居高临下.我以为你正在阅读纸质版本,并提出了一个更方便的选择. (6认同)
  • @Hector这就是为什么我们有带书签的PDF.跳转到**函数**部分(8.3.5),然后搜索"返回" (3认同)
  • @Barry:不需要居高临下.我在8.4中搜索了8.3.5的前两页.到那时,我以为我听不懂东西. (2认同)

Bas*_*tch 7

使用C++ 11(但不是以前版本的C++),您不仅可以返回类似C的函数指针,还可以返回C++ 闭包,特别是匿名函数.另请参见std :: function

标准不允许(从语义上讲,不是语法上 - 因此不是语法问题 ;请参阅Barry对引文的回答)返回函数(并且还禁止sizeof函数!)但允许返回函数指针.

顺便说一句,我不认为你可以返回整个功能.那是什么意思?你会如何实现?实际上,函数是一些代码块,它的名称(如数组)是指向函数机器代码开头的指针.

一个很好的技巧可能是在运行时构建(使用C++标准之外的机制)一个函数(然后处理它的函数指针).一些外部库可能允许的是:你可以使用JIT库(如asmjit,gccjit,LLVM ...),或简单地生成C++代码,然后编译并执行dlopendlsym进行它在POSIX系统等.

PS.您可能正确地理解C++ 11 语法(标准中的EBNF规则)不允许返回函数.这是一个用简单的英语表达的语义规则,它不允许(它不是任何语法规则).我的意思是单独的EBNF会允许:

 // semantically wrong... but perhaps not syntactically
 typedef int sigfun_T(std::string);
 sigfun_T foobar(int);
Run Code Online (Sandbox Code Playgroud)

并且出于语义原因(不是因为EBNF规则),编译器正确地拒绝上述代码.实际上,符号表对C++编译器很重要(它不是语法或上下文语法).

关于C++的可悲事实是(由于遗留原因)它的语法(单独)非常模糊.因此,C++ 11难以阅读(对于人类而言),难以编写(对于开发人员而言),难以解析(对于编译器而言),....

  • "标准禁止[s]返回功能"不回答"标准禁止[s]返回功能的哪一部分"的问题. (2认同)

jan*_*w a 5

using namespace std;

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

int main()
{
    hello()();
    auto r = hello();
    r();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 虽然此代码可以解决问题,但[包括解释](//meta.stackexchange.com/q/114762) 如何以及为何解决问题确实有助于提高帖子的质量,并可能会带来更多结果赞成票。请记住,您是在为将来的读者回答问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释并指出适用的限制和假设。 (3认同)