2017-03-27 43 views
1

私は最近、この好奇心を抱いた考えをCコードを処理する間に見つけました。
私は、この関数が正しく実関数の特定のプロパティを識別し、すなわち引数とは異なる関数へのポインタを返す関数を書くことはできますか?

double template_1(double (*)(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で:

は、今私はそれが聞かせて、別の関数を記述しなければなりませんでした。 私の質問は:derivativetemplate_1に変更せずに使用したいので、double (*)(double)という形式のものを派生して吐き出す関数を書くことは可能ですか?

私の考えはtypedef double (*real_function)(double); を定義し、その後、私はそれが何か吐き出すしたいと思います

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

を定義することでした:double derivative_2(double x)を。私はg(derivative) = double (*h)(double);のようなものを直接template_1 argument に定義することができました。残念ながら、私はこの仕事をどうやって作るか、あるいはそれがうまくいくかどうかについては、あまり気にしていません。

+0

この返された関数がすでに定義されている場合にのみ可能です。いいえ、実行時に関数を定義することはできません。これを行うには、HaskellやLispなどの関数型言語に切り替える必要があります。 –

+0

実行時にC言語で関数を作成する方法はありません( –

+0

@EugeneSh)。ほとんどの言語は、機能的なものだけでなく、これを(少なくとも何らかの形で)サポートしています - 例えば、C++、java、goなどです。 –

答えて

1

警告:以下のすべてがKerrekSB saidとしてC.

そうunidiomaticあるので、私は少しCの知識を持つC++開発者です、あなたはあなたの機能をいくつかの状態を運ぶ必要があります。これは生の関数では不可能ですが、状態を運ぶ構造体を定義し、この構造体で機能する関数を追加することができます。これは明らかに素晴らしい関数呼び出しの構文を失うという欠点があります。

#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; 
} 

を参照してください(入力制限によるわずかなvariatonは、)hereを実行している:私は例を手早く。

どのように動作しますか?私は構造体real_functionraw_real_functionderive_real_functionでいくつかの継承を偽装し、仮想関数呼び出しを生成しました。 struct real_functionは、エントリevaluateのみで構成される仮想関数テーブルのコンテナとして機能します。 「由来する」構造体関連する評価関数にこの関数ポインタポイント:

raw_real_functionインスタンスがmake_raw_real_functionで初期化として(evaluate_raw_real_functionを指すderive_real_functionインスタンスはevaluatemake_derivativeで初期化としてderive(指し示す

evaluateを呼び出すとき。 real_function_baseメンバでは、関連する評価関数が呼び出され、real_function*が関連する構造体ポインタにキャストされ、その情報に必要な処理が実行されます。

すべてはちょうどreal_function*なので、私たちはそれらを自由に連鎖させることができますが、通常の機能をreal_function形式に変換する必要があります。それはmake_raw_real_functionです。

+0

答えを理解するのにかなり時間がかかりました。ありがとう、ありがとう。ここでの主な教訓は、C++についてもっと学ぶことです – Fra

2

Cで匿名の機能を実行するには、いくつかの方法があります。コメントによると、移植性がありません。しかし、ユースケースに応じて、あなたはこれが役立つことがあります。Anonymous functions using GCC statement expressions

人のカップルは、彼らがどのようにポータブル必ず、同様の問題を持っていないように見えてきたが、彼らは機知になることがあります。基本的には https://github.com/graphitemaster/lambdapp https://github.com/Leushenko/C99-Lambda

、匿名関数を必要としない方法でプログラムを設計する方法があれば、そのようにしてください。あなたが他の選択肢がない場合、私はこれらのショットの1つを与えるだろう。

+0

私はそれを見ていただきありがとうございます! – Fra

1

あなたは機能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); 
+0

それはすばらしい解決策ですが、私が探していたものではありません。 – Fra

関連する問題