【问题标题】:Is it possible to write a function which returns a pointer to a function different from the function in its argument?是否可以编写一个函数,该函数返回指向与其参数中的函数不同的函数的指针?
【发布时间】:2017-03-27 19:24:10
【问题描述】:

我最近在处理 C 代码时偶然发现了这个奇怪的想法。
我写了一个函数,它返回一个双精度,并将指向函数的指针和一定数量的参数作为参数,即

double template_1(double (*)(double),...);

这个函数正确地识别了一个真实函数的某个属性

 double f(double ); 

template_1 中表示为一个指针,以便使template_1 对我可能插入的每个实际功能都有效。

现在我不得不写另一个函数,顺其自然:

double derivative(double (*)(double),double);

double derivative(double (*f)(double),double x){

    double epsilon = ...; 

    return ( f(x+epsilon)-f(x-epsilon) )/(2.0*epsilon);
}

再次在参数中添加 f 以使其适用于每个 f。 我的问题是:既然我想在template_1 中使用derivative 而不修改它,是否可以编写一个函数来获取导数并吐出double (*)(double ) 形式的东西?

我的想法是定义typedef double (*real_function)(double); 然后定义

real_function g(double (*derivative)(double (*)(double),double ) )

我希望它吐出类似的内容:double derivative_2(double x);这样我就可以直接在template_1 argument 中定义类似g(derivative) = double (*h)( double); 的内容 不幸的是,我不知道如何使这项工作发挥作用,或者即使它可以工作。

【问题讨论】:

  • 只有在这个返回的函数已经定义的情况下才有可能。不,您不能在运行时“定义”函数。为此,您将不得不切换到一些函数式语言,例如 Haskell 或 Lisp。
  • 没有(便携式)方法可以在 C 中运行时创建函数。
  • @EugeneSh。大多数语言,而不仅仅是函数式语言,都支持这一点(至少以某种形式)——例如 C++、java、go。
  • @PaulHankin 对此不确定。我更熟悉函数式函数 :) 高阶函数和柯里化在那里非常自然。
  • 您基本上是在要求某种有状态的函数,您可以在 C 中通过向每个函数添加一个不透明的上下文参数来实现它,并使用它来存储状态。

标签: c function pointers function-pointers


【解决方案1】:

有几种方法可以在 C 中执行匿名函数。正如 cmets 所说,它们不可移植。但根据用例,您可能会发现这很有用:Anonymous functions using GCC statement expressions

一些人似乎有类似的问题,不确定他们的便携性,但他们可能是足智多谋的: https://github.com/graphitemaster/lambdapp https://github.com/Leushenko/C99-Lambda

基本上,如果有一种不需要匿名函数的方式来构建程序,那么就这样做。如果您别无选择,那么我会试一试。

【讨论】:

    【解决方案2】:

    警告:我是一名 C++ 开发人员,对 C 知识知之甚少,因此接下来的所有内容都可能是单一的 C。

    作为KerrekSB said,您需要在函数中携带一些状态。这对于原始函数是不可能的,但您可以定义一个携带状态的结构并添加一个与该结构一起使用的函数。这显然具有失去良好的函数调用语法的缺点。我举了一个例子:

    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef double (*raw_fptr)(double);
    struct real_function;
    typedef double (*evaluate_function)(struct real_function*, double);
    
    struct real_function {
            evaluate_function evaluate;
    };
    typedef struct real_function real_function;
    
    double evaluate(real_function *f, double x) {
            if(f) {
                    return f->evaluate(f, x);
            }
            return NAN;
    }
    
    struct raw_real_function {
            real_function real_function_base;
            raw_fptr raw_function;
    };
    typedef struct raw_real_function raw_real_function;
    
    double evaluate_raw_real_function(real_function *f_base, double x) {
            if(f_base) {
                    raw_real_function *f = (raw_real_function*)f_base;
                    return f->raw_function(x);
            }
            return NAN;
    }
    
    raw_real_function make_raw_real_function(raw_fptr function) {
            raw_real_function result;
            result.raw_function = function;
            result.real_function_base.evaluate = evaluate_raw_real_function;
            return result;
    }
    
    struct derive_real_function {
            real_function real_function_base;
            real_function *function_to_derive;
    };
    typedef struct derive_real_function derive_real_function;
    
    double derive(real_function *f_base, double x) {
            derive_real_function *f = (derive_real_function*)f_base;
            double epsilon = 1e-3;
            double upper = evaluate(f->function_to_derive, x+epsilon);
            double lower = evaluate(f->function_to_derive, x-epsilon);
            double result =  (upper - lower)/(2.0*epsilon);
            return result;
    }
    
    derive_real_function make_derivative(real_function * function_to_derive) {
            derive_real_function result;
            result.real_function_base.evaluate = derive;
            result.function_to_derive = function_to_derive;
            return result;
    }
    
    double x_cubed(double x) {
            return x * x * x;
    }
    
    int main(int argc, char **argv) {
            raw_real_function x_cubed_wrapped = make_raw_real_function(x_cubed);
            derive_real_function derived = make_derivative(&x_cubed_wrapped.real_function_base);
            derive_real_function derived_twice = make_derivative(&derived.real_function_base);
            double x = atof(argv[1]);
            double derivative = evaluate(&derived.real_function_base, x);
            double second_derivative = evaluate(&derived_twice.real_function_base, x);
            printf("derivative of x^3 at %f = %f\n", x, derivative);
            printf("second derivative of x^3 at %f = %f\n", x, second_derivative);
            return 0;
    }
    

    请参阅(由于输入限制,略有变化)运行here

    它是如何工作的?我用结构real_functionraw_real_functionderive_real_function 伪造了一些继承来生成虚函数调用。 struct real_function 用作仅包含条目evaluate 的虚函数表的容器。此函数指针指向“派生”结构的相关评估函数:

    raw_real_function 实例指向evaluate_raw_real_function(在make_raw_real_function 中初始化。derive_real_function 实例将evaluate 指向derive(在make_derivative 中初始化)。

    real_function_base 成员上调用evaluate 时,它将调用关联的评估函数,该函数将real_function* 转换为其关联的结构指针,并使用该信息执行所需的操作。

    由于一切都只是一个real_function*,我们可以随意将它们链接起来,但需要将“普通”函数转换为real_function格式,这就是make_raw_real_function所做的。

    【讨论】:

    • 我花了很长时间才明白答案,非常感谢。我想这里的主要教训是我将更多地了解 C++
    【解决方案3】:

    如果你有函数my_fancy_function:

    double my_fancy_function (double x) { return sin(x) + cos(x); }
    

    然后,您可以使用辅助宏来为您创建派生函数。

    #define DEFINE_DERIVATIVE_OF(FUNC) \
    double derivative_of_ ## FUNC (double x) { \
        return derivative(FUNC, x); \
    }
    
    DEFINE_DERIVATIVE_OF(my_fancy_function)
    

    然后您将这个新定义的函数传递给您的模板。

    template_1(derivative_of_my_fancy_function, x, y, z);
    

    【讨论】:

    • 这是一个很棒的解决方案,但并不是我想要的。
    猜你喜欢
    • 2020-01-12
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多