38

function へのポインタがあるとします_stack_push(stack* stk, void* el)curry(_stack_push, my_stack)を受け取るだけの関数を呼び出して取得できるようにしたいvoid* el。C ではランタイム関数の定義が許可されていないため、それを行う方法は思いつきませんでしたが、ここには私よりもはるかに賢い人がいることは知っています :)。何か案は?

4

6 に答える 6

21

C/C++/Objective-C でのカリー化について説明している Laurent Dami による論文を見つけました。

カリー化された関数を使用した C/C++/Objective-c でのより機能的な再利用性

Cでの実装方法に興味があります:

現在の実装では、既存の C コンストラクトを使用してカリー化メカニズムを追加しています。これは、コンパイラを変更するよりもはるかに簡単で、カリー化の利点を証明するのに十分です。ただし、このアプローチには 2 つの欠点があります。まず、カリー化された関数は型チェックできないため、エラーを避けるために慎重に使用する必要があります。第 2 に、カリー関数は引数のサイズを知ることができず、それらがすべて整数のサイズであるかのようにカウントします。

このペーパーには の実装は含まれていませんが、関数ポインタ可変個引数関数curry()を使用して実装する方法を想像することができます。

于 2009-06-21T05:25:31.030 に答える
8

GCC は、ネストされた関数の定義の拡張機能を提供します。これは ISO 標準 C ではありませんが、質問に非常に簡単に答えることができるので、これは興味深いかもしれません。つまり、ネストされた関数は親関数のローカル変数にアクセスでき、それらへのポインターは親関数からも返すことができます。

以下は、短い自明の例です。

#include <stdio.h>

typedef int (*two_var_func) (int, int);
typedef int (*one_var_func) (int);

int add_int (int a, int b) {
    return a+b;
}

one_var_func partial (two_var_func f, int a) {
    int g (int b) {
        return f (a, b);
    }
    return g;
}

int main (void) {
    int a = 1;
    int b = 2;
    printf ("%d\n", add_int (a, b));
    printf ("%d\n", partial (add_int, a) (b));
}

ただし、この構造には制限があります。次のように、結果の関数へのポインターを保持する場合

one_var_func u = partial (add_int, a);

読み取り対象の変数が終了直後に破棄されたため、関数呼び出しu(0)は予期しない動作を引き起こす可能性があります。aupartial

GCC のドキュメントのこのセクションを参照してください。

于 2012-06-12T12:44:04.510 に答える
4

これが私の頭の上からの最初の推測です(最良の解決策ではないかもしれません)。

カレー関数は、ヒープからメモリを割り当て、パラメータ値をそのヒープ割り当てメモリに入れることができます。秘訣は、返された関数が、ヒープに割り当てられたメモリからパラメーターを読み取ることになっていることを認識することです。返された関数のインスタンスが 1 つしかない場合は、それらのパラメーターへのポインターをシングルトン/グローバルに格納できます。それ以外の場合、返された関数のインスタンスが複数ある場合、カレーは返された関数の各インスタンスをヒープ割り当てメモリに作成する必要があると思います(「パラメーターへのポインターを取得する」、「パラメーターをプッシュする」、「他の関数を呼び出す」などのオペコードをヒープ割り当てメモリに書き込むことにより)。その場合、割り当てられたメモリが実行可能かどうかに注意する必要があり、おそらく (私にはわかりませんが) ウイルス対策プログラムを恐れることさえあります。

于 2009-06-21T05:32:05.283 に答える