1

私はC++を使用してコードを開発しており、Cで開発されているがC++でコンパイルできるMPFIT非線形カーブフィッティングライブラリを使用したいと考えています。

たとえば、「myClass」という名前のクラスがあり、このクラスには関数myClass :: Execute()があります。

myClass.hファイルに「mpfit.h」を含めます。そして、Execute()からmpfitという関数を呼び出してみてください。

int status = mpfit(ErrorFunction, num1, num2, xsub_1D, 0, 0, (void *) &variables, &result);

問題は、ErrorFunctionがmyClassの関数であるということです。したがって、これを使用しようとすると、コンパイラはエラーを出します。ErrorFunctionをクラスオブジェクトから実行しようとしましたが、今回は以下のエラーが発生します。

ErrorFunctionがクラス外にある場合のエラー:

エラー4エラーC2664:'mpfit':パラメータ1を'int(__cdecl *)(int、int、double *、double、double *、void *)'から'mp_func'に変換できません

ErrorFunctionがクラス内にある場合のエラー:

Error   3   error C3867: 'myClass::ErrorFunction': function call missing argument list; use '&myClass::ErrorFunction' to

エラー関数の定義:

int ErrorFunction(int dummy1, int dummy2, double* xsub, double *diff, double **dvec, void *vars)

この関数を呼び出して、C関数であるmpfitに解析するにはどうすればよいですか?

mp_funcと定義されている:

/* Enforce type of fitting function */
typedef int (*mp_func)(int m, /* Number of functions (elts of fvec) */
               int n, /* Number of variables (elts of x) */
               double *x,      /* I - Parameters */
               double *fvec,   /* O - function values */
               double **dvec,  /* O - function derivatives (optional)*/
               void *private_data); /* I/O - function private data*/
4

5 に答える 5

4

呼び出し規約が一致していることを確認してください。C ライブラリは、C 呼び出し規約、つまり cdecl (__cdecl) を使用します。C++ 内で mp_func typedef を使用している場合は、コンパイラの標準呼び出し規約または stdcall (__stdcall) にデフォルト設定されている可能性があります。新しい typedef を作成するか、次のように変更します。

typedef int __cdecl (*mp_func)(int m, /* Number of functions (elts of fvec) */
               int n, /* Number of variables (elts of x) */
               double *x,      /* I - Parameters */
               double *fvec,   /* O - function values */
               double **dvec,  /* O - function derivatives (optional)*/
               void *private_data); /* I/O - function private data*/

また、ErrorFunction を宣言するときは、__cdecl としても宣言します。

int __cdecl ErrorFunction(int, int, double*, double *, double **, void *);

mpfit 関数を呼び出したときにコンパイラが引き続きエラーを出す場合は、cdecl を使用して関数ポインターを mp_func typedef にキャストしてみてください。

int status = mpfit((mp_func)ErrorFunction, num1, num2, xsub_1D, 0, 0, (void *) &variables, &result);
于 2012-05-17T21:42:33.527 に答える
3

あなたが示したmpfit()との定義を考えると、のパラメータを使用してクラスのポインタを渡す必要があります。現在、代わりにそのパラメーターを使用してアイテムを渡しています。クラスのメンバーになり (まだメンバーになっていない場合)、代わりに次のように渡します。mp_funcprivate_datamp_functhisvariablesvariablesthismpfit()

class MyClass
{
private:
    TheDataType variables;
    static int ErrorFunction(int m, int n, double *x, double *fvec, double **dvec, MyClass *pThis);
public:
    void DoIt();
};

void MyClass::DoIt()
{
    // ...
    int status = mpfit((mp_func)&ErrorFunction, num1, num2, xsub_1D, 0, 0, this, &result); 
    // ...
}

int MyClass::ErrorFunction(int m, int n, double* x, double *fvec, double **dvec, MyClass *pThis)
{
    // use pThis->variables as needed ...
} 

または:

class MyClass
{
private:
    static int MPFitErrorFunction(int m, int n, double *x, double *fvec, double **dvec, MyClass *pThis);
    int MyErrorFunction(int m, int n, double *x, double *fvec, double **dvec);
public:
    void DoIt();
};

void MyClass::DoIt()
{
    // ...
    int status = mpfit((mp_func)&MPFitErrorFunction, num1, num2, xsub_1D, 0, 0, this, &result); 
    // ...
}

int MyClass::MPFitErrorFunction(int m, int n, double* x, double *fvec, double **dvec, MyClass *pThis)
{
    return pThis->MyErrorFunction(m, n, x, fvec, dvec);
} 

int MyClass::MyErrorFunction(int m, int n, double* x, double *fvec, double **dvec)
{
    // use this->variables as needed ...
} 
于 2012-05-17T16:59:33.570 に答える
1

の代わりに見える:

int ErrorFunction(int dummy1, int dummy2, double* xsub, double diff, double *dvec, void *vars)

そのはず:

int ErrorFunction(int dummy1, int dummy2, double* xsub, double *diff, double **dvec, void *vars)

あなたに合うように

typedef int (*mp_func)(int m, /* Number of functions (elts of fvec) */
               int n, /* Number of variables (elts of x) */
               double *x,      /* I - Parameters */
               double *fvec,   /* O - function values */
               double **dvec,  /* O - function derivatives (optional)*/
               void *private_data); /* I/O - function private data*/
于 2012-05-17T16:44:09.473 に答える
1

これが機能するには、コールバックを宣言extern "C"する必要があります。

編集: 人々がこの事実を理解するのに苦労しているように見えます。標準は言う(7.5 / 1):

言語リンケージが異なる 2 つの関数型は、それ以外は同一であっても、別個の型です。

于 2012-05-17T17:01:22.723 に答える
0

pimpl イディオムを使用して、C++ から C への標準イディオムがあります。

foo_c.h:

#ifdef __cplusplus
extern "C" {
#endif
//forward declaration.  clients of foo_c.h should only hold pointers to Foo_c
typedef struct Foo_c Foo_c;

int someMethod(Foo_c* foo);
#ifdef __cplusplus
}
#endif

foo_c.cpp:

#include <foo.h>
struct Foo_c {
       Foo foo;
}
int someMethod(Foo_c* foo) { 
     try {
         foo->foo.someMethod();
         return 0; //no error
     }
     catch(...) {
         return 1; //error
     }
}

(以下の回答ごとにextern「C」用に編集。)

于 2012-05-17T16:50:45.500 に答える