2013-03-07 131 views
1

請考慮下面的代碼,它包含在我製作的庫中。如何編寫在C++中使用其他函數的函數

#include <complex> 

std::complex<double> besselJ(int order, std::complex<double> z) 
{ 
    // Function call 
} 

std::complex<double> besselH1(int order, std::complex<double> z) 
{ 
    // Function call 
} 

注意兩個函數都有相同的簽名。現在,我想編寫第三個函數,它執行的操作與besselJbesselH1完全相同。我嘗試以下

template<std::complex<double> (*T)(int, std::complex<double>)> 
std::complex<double> diffBessel(int order, std::complex<double> z) 
{ 
    return T(order-1, z)-T(order+1,z); 
} 

當一個成員函數嘗試使用語法diffbessel<besselJ>(int, std::complex<double>,GCC抱怨說the value of 'besselJ' is not usable in a constant expression。有關說明,請參閱this answer

有沒有辦法做一些像上面的模板代碼,如果它的工作而不是訴諸於struct小號包裝besselJbesselH1會做什麼?我認爲結構會增加不必要的複雜性。

更新:這個工程很漂亮,就像@aschepler建議它應該那樣。實際代碼中存在名稱衝突。這花了額外的第1001次看看。我被其他StackOverflow文章弄糊塗了,這些文章暗示這不起作用,因爲函數指針是可變的。

+1

鏈接的答案並不能解釋爲什麼'diffbessel (args)'不起作用。據我所知,它應該工作。 – aschepler 2013-03-07 21:47:00

+0

你能顯示GCC抱怨的確切代碼嗎? – Angew 2013-03-07 21:56:43

+0

感謝你們倆。它**可以**工作。儘管我看了幾個小時的代碼,但我忽略了一個愚蠢的錯誤。 – 2013-03-07 22:12:46

回答

4

的前提:

只要besselJ在你的例子是功能的名稱,而不是一個變量你正在使用的模板參數,然後通過一個函數指針作爲非類型的模板參數應該工作。

查看live example

替代解決方案:

如果你的函數指針在其值計算在運行時的變量舉行,你將不會被允許使用該函數指針作爲模板參數。如果你想使用一個運行時函數指針,你可以只使用一個普通功能參數,而不是一個模板參數:

#include <complex> 

std::complex<double> diffBessel(
    std::complex<double> (*fxn)(int, std::complex<double>), 
    int order, 
    std::complex<double> z 
    ) 
{ 
    return fxn(order-1, z) - fxn(order+1,z); 
} 

更地道SOLUTION:(需要C++ 11)

如果你想要更多的靈活性,C++ 11可以使用std::function<>

#include <complex> 
#include <functional> 

std::complex<double> diffBessel(
    std::function<std::complex<double>(int, std::complex<double>)> fxn, 
    int order, 
    std::complex<double> z 
    ) 
{ 
    return fxn(order-1, z)- fxn(order+1,z); 
} 

在這兩種情況下,你的函數可以調用這種方式:

int main() 
{ 
    std::complex<double> c; 
    /* ... */ 
    diffBessel(besselH1, 2, c); 
} 

另一個可能性:

作爲另一種可能性,如果你不想或者不能使用std::function<>,你可以讓你的功能,通過使模板接受任何調用對象:

template<typename F> 
std::complex<double> diffBessel(
    F f, 
    int order, 
    std::complex<double> z 
    ) 
{ 
    return f(order-1, z) - f(order+1,z); 
} 

同樣,您將調用此方法與調用以前版本的方式完全相同。

+0

我想過使用'std :: function',但在[文章](http://stackoverflow.com/questions/9054774/difference-between-stdfunction-and-a-standard-function-pointer)比較'std :: function'和函數指針,除非需要額外的功耗,否則不鼓勵使用'std :: function'。 – 2013-03-07 22:16:52

+0

@JoeyDumont:決定是否使用'std :: function'主要是基於你的用例。 'std :: function'允許更多的靈活性(你可以傳入一個lambda,一個函數,任何東西),它的「壞」性能(在大多數情況下是虛函數調用)只有在你證明它時纔會成爲問題成爲瓶頸。否則,你應該關注乾淨的設計。這就是說,你不需要*使用'std :: function'。你可以使用常規函數指針,但是作爲函數參數,而不是模板參數。 – 2013-03-07 22:20:04

+0

@JoeyDumont:無論如何,正如我在答案的開頭寫的那樣,只要你沒有傳入*變量*的值,模板參數也應該適用於你的情況。如果你是,也就是說,如果要在運行時確定要使用的函數,那麼你幾乎不得不使用函數參數而不是模板參數:是選擇常規指針還是選擇std :: function '取決於你。就我個人而言,我會去第二個。 – 2013-03-07 22:21:43

3

模板需要在編譯時知道它們的參數。在運行時將模板參數拉出變量不起作用。

只需將函數指針作爲函數參數即可。它不需要是模板功能。

std::complex<double> diffBessel(int order, 
           std::complex<double> z, 
           std::complex<double> (*T)(int, std::complex<double>)) 
+0

確實,但這失敗了,因爲我有另一個函數,使用基地函數'diffBessel'。我需要一個可變數量的函數指針,而這絕對不是最好的。不過謝謝你的想法。 – 2013-03-07 22:11:28

相關問題