function へのポインタがあるとします_stack_push(stack* stk, void* el)
。curry(_stack_push, my_stack)
を受け取るだけの関数を呼び出して取得できるようにしたいvoid* el
。C ではランタイム関数の定義が許可されていないため、それを行う方法は思いつきませんでしたが、ここには私よりもはるかに賢い人がいることは知っています :)。何か案は?
6 に答える
C/C++/Objective-C でのカリー化について説明している Laurent Dami による論文を見つけました。
カリー化された関数を使用した C/C++/Objective-c でのより機能的な再利用性
Cでの実装方法に興味があります:
現在の実装では、既存の C コンストラクトを使用してカリー化メカニズムを追加しています。これは、コンパイラを変更するよりもはるかに簡単で、カリー化の利点を証明するのに十分です。ただし、このアプローチには 2 つの欠点があります。まず、カリー化された関数は型チェックできないため、エラーを避けるために慎重に使用する必要があります。第 2 に、カリー関数は引数のサイズを知ることができず、それらがすべて整数のサイズであるかのようにカウントします。
このペーパーには の実装は含まれていませんが、関数ポインタと可変個引数関数curry()
を使用して実装する方法を想像することができます。
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)
は予期しない動作を引き起こす可能性があります。a
u
partial
GCC のドキュメントのこのセクションを参照してください。
これが私の頭の上からの最初の推測です(最良の解決策ではないかもしれません)。
カレー関数は、ヒープからメモリを割り当て、パラメータ値をそのヒープ割り当てメモリに入れることができます。秘訣は、返された関数が、ヒープに割り当てられたメモリからパラメーターを読み取ることになっていることを認識することです。返された関数のインスタンスが 1 つしかない場合は、それらのパラメーターへのポインターをシングルトン/グローバルに格納できます。それ以外の場合、返された関数のインスタンスが複数ある場合、カレーは返された関数の各インスタンスをヒープ割り当てメモリに作成する必要があると思います(「パラメーターへのポインターを取得する」、「パラメーターをプッシュする」、「他の関数を呼び出す」などのオペコードをヒープ割り当てメモリに書き込むことにより)。その場合、割り当てられたメモリが実行可能かどうかに注意する必要があり、おそらく (私にはわかりませんが) ウイルス対策プログラムを恐れることさえあります。