10

我想创建一个通用函数,它返回指向 C/C++ 中另一个函数的函数指针。但是,第二个返回的函数应该能够使用第一个函数中的变量。

例子,

typedef double (*func_t)(double);

func_t inverse(func_t fn) {
   // define another function here that uses fn
   double solve(double x) {
      // use fn
   }
   return &solve;
}

double sqr(double x) { return x * x; }

int main() {
     func_t inv = inverse(sqr);
     printf("sqrt %d = %f\n", 100, inv(100)); 
}

显然 gcc、g++ 不允许我这样做。我可以在不使用类或结构的情况下实现这一点吗?

4

8 回答 8

5

这与嵌套函数无关;这是关于闭包的。GCC 的嵌套函数是一种半实现形式的闭包,它不能满足问题的要求。

C,按照任何标准,根本不支持闭包。

C++11 通过 lambda 支持闭包,还有一些其他特定于 C++ 的解决方案。

Apple 的 Clang 编译器确实支持闭包作为 C 模式中的扩展,以“块”的形式。与嵌套函数不同,这些函数实际上适用于请求的用例(即返回到更高的调用级别)。

你可以这样写:

typedef double (^func_t)(double);  // block type is slightly different from function pointer

func_t inverse(func_t fn) {
   return ^ double(double x) {
       //use fn
   };
}

// ...etc., same from here

但是如果你想广泛使用闭包,你真的需要使用不同的语言。由于缺乏任何类型的内存管理,您将在 C 中遇到严重的并发症(无限制的闭包是手动管理的噩梦)。

于 2013-10-22T20:39:39.073 回答
4

回答 C:

C 不支持嵌套函数(在另一个函数中定义一个函数),但gcc允许它作为 C 的 GNU 扩展。

http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html

于 2013-10-22T19:27:54.080 回答
4

这在带有 lambda 的 C++11 中是可能的:

#include <cstdio>
#include <cmath>
#include <functional>

typedef std::function<double(double)> func_t;

func_t inverse(func_t fn) {
    return [=](double x) { printf("fn(x): %f\n", fn(x)); return sqrt(x); };
}

double sqr(double x) { return x * x; }

int main() {
    auto inv = inverse(sqr);
    printf("sqrt %d = %f\n", 100, inv(100));
}
于 2013-10-22T19:39:27.670 回答
2

If you can use C++11, them lambda functions are your friend:

#include <functional>
#include <iostream>

std::function<double(double)> identity(std::function<double(double)> fn)
{
  return [fn](double x){
    // Do your logic here
    return fn(x);
  };
}

double sqr(double x) { return x * x; }

int main() {
  auto f = identity(sqr);
  std::cout << "sqr(100) = " << f(100) << std::endl;
}

If you don't plan to support C++11, you can do this way:

#include <iostream>

typedef double (*func_t)(double);
struct func
{
  func_t fn;
  double (*calc)(func_t, double);
  double operator()(double x) {return calc(fn, x);}
};

double identity_calc(func_t fn, double x) {return fn(x);}

func identity(func_t fn)
{
  func f = {fn, identity_calc};
  return f;
}

double sqr(double x) { return x * x; }

int main() {
  func f = identity(sqr);
  std::cout << "sqr(100) = " << f(100) << std::endl;
}

But I don't think you will have much luck with plain C.

于 2013-10-22T19:53:36.547 回答
1

在 c 中的函数内部定义一个函数?

称为嵌套函数。

嵌套函数不是ANSI C的一部分,但是,它们是 Gnu C的一部分。

来自维基百科

支持词法嵌套函数的知名语言包括:

基于 ALGOL 的语言,例如 ALGOL 68、Simula、Pascal、Modula-2、Modula-3、Oberon、Seed7 和 Ada。

现代版本的 Lisp(具有词法范围),例如 Scheme 和 Common Lisp。

ECMAScript(JavaScript 和 ActionScript)。

斯卡拉(完全支持)

对脚本语言如 Ruby、Python、Perl(从版本 6 开始)的不同程度的支持。

标准 C 和 C++ 不支持嵌套函数,但是:GCC 支持 C 中的嵌套函数,作为语言扩展。

与 C 相关的 D 语言具有嵌套函数。

Fortran,从 Fortran-90 开始,支持一级嵌套(CONTAINed)子例程和函数。

MATLAB(完全支持)

GNU C 语法示例(使用嵌套函数进行 C 扩展):

float E(float x)
{
    float F(float y)
    {
        return x + y;
    }
    return F(3) + F(4);
}
于 2013-10-22T19:31:02.773 回答
1

标准 C 中不允许嵌套函数

但是它们可以 作为 GCC 中的语言扩展使用

由于问题是用 C++ 标记的。C++ 也不支持嵌套函数。您可能有这样的解决方法:-

int main() 
{
  struct ABC {
    static void xyz()
    {
    }
  };

  ABC::xyz();

  return 0;
}

即,您可以有本地课程。

于 2013-10-22T19:31:24.493 回答
1

comp.lang.c 常见问题列表 · 问题 20.24

实现嵌套函数并不是微不足道的,这样它们就可以正确访问包含函数中的局部变量,因此为了简化它们,故意将它们排除在 C 之外。(作为扩展,gcc 确实允许它们。)对于嵌套函数的许多潜在用途(例如 qsort 比较函数),一个适当但稍微麻烦的解决方案是使用具有静态声明的相邻函数,必要时通过一些静态变量进行通信。(虽然 qsort 不支持更简洁的解决方案,但它是传递指向包含必要上下文的结构的指针。)

于 2013-10-22T19:57:06.360 回答
-1

通常你在一个额外的文件/模块中编写你的函数。使您的内部功能静态化,外部任何人都无法使用它。

制造

于 2013-10-22T19:35:01.950 回答