2011-10-13 69 views
2

我有一堆成員函數執行一些數學運算並返回結果。例如:「自動」爲C++成員函數創建非成員包裝

class Foo { 
public: 
    double f(double); 
    double g(double); 
    double h(double); 
    // ... 
} 

double Foo::f(double foo1) { 
    // ... 
} 
// and so on 

在程序的幾點我的工作,我需要數值積分的一些功能。我想用數值積分例程有簽名

extern "C" double qgauss(double (*func)(double, void*), void* data, 
         double a, double b); 

,從我一直在閱讀似乎傳遞成員函數的整合程序的最佳方法是創建包裝函數:

double f_wrapper(double x, void* data) { 
    return ((Foo*)data)->f(x); 
} 

但隨着十幾個成員函數fgh等來包裝,或許更要在以後添加,這得到相當重複的。可以(或者應該)我使用模板或宏或某些東西來壓縮我必須編寫的代碼量來創建這些包裝函數?


順便說一句,我目前使用的解決方案是重新實現一體化例程作爲接受直接在物體參數C++函數模板:

template <class C> double qgauss(C* obj, double (C::*func)(double), 
           double a, double b) { 
    // ... 
} 

但是這涉及大規模重複的代碼,我不喜歡。如果任何人比創建封裝函數或者實現C++版本的集成器都有更好的解決方案,我會有興趣聽到它,並且我可以提出一個單獨的問題,如果這會更合適。

+0

如果只有一個Foo類的實例,你可以讓所有的方法都是靜態的嗎?那麼函數變成Foo :: f(x)而不是foo-> f(x)? – abelenky

+0

我可以,但函數'f'等確實需要訪問'Foo'中的成員變量。因此,如果我將它們全部設爲靜態,訪問變量的語法將全部搞亂,因爲我不得不明確引用實例,這首先會挫敗使用類的點。 –

+0

我會爲此使用一個宏。與我寫的一些相比,它會相當溫順。 – IronMensan

回答

2

您可以用模板嘗試:

template <class C, C::*Func> 
double wrapper(double x, void* data) { 
    return ((C*)data)->*Func(x); 
} 

qgauss(&wrapper<C, &C::f>, data, a, b); 

現在,我還沒有試過這一點,因爲你想一個函數,它是一個模板的地址,可能會出現一些問題 - 更糟糕的是我認爲你在技術上需要一個extern "C"函數。如果上述確實是死路一條,我認爲你應該只使用宏,因爲畢竟這是你在這個時候正在做的C編程,而宏是自然的。

+0

模板在編譯時被解析,並且在連接方面,extern「C」只是防止名稱重組。這看起來像一個很好的解決方案 – Dave

+1

@Dave調用約定也可能在'extern「C」'和C++之間有所不同,但這取決於編譯器和編譯器設置。例如。 __cdecl和__stdcall之間的Visual Studio堆棧清理差異(當命令行中存在/ Gz時,後者是默認值):http://msdn.microsoft.com/en-us/library/984x0h58.aspx – Sjoerd

+0

好點。 '__cdecl double wrapper(...)'是否足夠? – Dave