2014-11-03 113 views
0

我使用優化工具箱中的函數,該函數以數值方式計算函數的導數。它接受一個指向具有一個參數的函數的指針,但是如果我需要將指針傳遞給一個帶有多個參數的函數,並期望只傳遞其他較不重要的參數呢?指向具有多個參數作爲函數參數的函數

//Function from toolbox 
double num_differentation(double (func(const double)), double x) 
{ 
//makes various calls to func, but with only one parameter 
func(x); 
} 

現在假設我有一個功能,我想傳遞給以上,但其中有額外的參數並不直接相關的優化問題,但仍然是需要在該函數有意義的結果到達。

double my_func_to_be_input(double a, double b, double c) { 
return a+b*c; 
} 

有沒有辦法重寫num_differentiation,以便在調用func時它會通過所有三個參數?我嘗試以下,但它沒有工作:

double num_differentation(double (func(const double arg1, const double arg2, const double arg3)), double x) 
{ 
//makes various calls to func, but with only one parameter 
func(x, arg2, arg3); 
} 

如果我們想更加花哨,將有可能爲num_differentiation接受功能與不相干的人只是被穿過不同的參數號?

在任何情況下,我不想訴諸全局變量來路由這些額外的參數。

我正在使用Visual Studio 2013,並歡迎任何有用的建議,尤其是具體的代碼示例。

更新: 這就是我解決它的方法。

//Rewritten function from toolbox 
double rewritten_num_differentation(std::function<double(double)> func, double x) 
{ 
func(x); 
} 

在我的主要代碼:

using namespace std::placeholders;  
auto my_func_to_be_input_with_forwarded_arguments= std::bind(my_func_to_be_input, _1, second_argument_to_be_forwarded, third_argument_to_be_forwarded); 

return rewritten_num_differentiation(my_func_to_be_input_with_forwarded_arguments, x_arg); 

這類似於CrazyEdie建議的第一個解決方案。也許還有更優雅的方法不涉及重寫工具箱功能,但將std :: function類型轉換爲C風格函數指針似乎非常複雜(就像他們在這裏嘗試http://www.cplusplus.com/forum/general/63552/)。

+0

要在編譯時執行此操作,可以使用可變參數模板。我不確定VS2013的支持會有多好。 – 2014-11-03 05:37:09

+0

代替你可能不得不使用一個解決方案,比如讓'func'接受一個參數向量。 – 2014-11-03 05:37:58

回答

0

一個精心設計的空調風格工具箱將有原型是:

//Function from toolbox 
double num_differentation(double (func(const double, void*)), 
          double x, 
          void * user_data) 
{ 
//makes various calls to func, but with only one parameter 
func(x, user_data); 
} 

,然後期望用戶編寫

typedef struct my_data { int p; } my_data 
double func(double x, void * user_data) { 
    my_data * data = (my_data*)user_data; 
    return pow(x, data->p); 
} 

而且你會使用這樣的庫:

my_data data; 
data.p = 7; 
num_differentiation(&func, 3.0, &data); 

然而,它聽起來像是被一個令人討厭的工具箱所困住,而「標準」就是使用t o使用全局,而不是傳遞用戶數據。

my_data g_data; 
double func(double x) { 
    return pow(x, g_data.p); 
} 

然後使用它像

g_data.p=7; 
num_differentiation(&func, 3.0); 
+0

注意精心設計的C++工具箱的樣式是完全不同的,但許多數值工具箱是C而不是C++,而且您的代碼當然使用C樣式庫。 – 2014-11-03 05:46:54

+0

問題的工具箱的確是數字食譜2.1,它們非常類似於C,儘管它們使用C++的命名空間和其他特性。我不確定最近的第3版在這方面是否更好。 – Steve06 2014-11-03 14:51:11

+0

我給你+1提醒我如何以老式的C方式做到這一點。 – Steve06 2014-11-03 16:38:19

2
double num_differentials(std::function<double(double)> fun, double x) 
{ 
    return fun(x); 
} 

auto n = num_differentials(std::bind(&fun, _1, arg1, arg2), x); 

或者:

auto n = num_differentials([arg1,arg2](double x) { return fun(x,arg1,arg2); }, x); 

相信無論是應VC2013工作。

編輯迴應更新:

這不是所有的辛苦包了std::function爲通過C回調系統呼叫。

假設:

void register_callback(double (*fun)(double,void*), void* client_data); 

這樣寫:

double wrap_legacy(double d, void* client_data) 
{ 
    auto fun = static_cast<std::function<double(double)>*>(client_data); 
    return (*fun)(d); 
} 

或者,如果你想添加一些安全性,這一點:

double wrap_legacy(double d, void* client_data) 
{ 
    auto any = static_cast<boost::any*>(client_data); 
    auto fun = boost::any_cast<std::function<double(double)>>(*any); 
    return fun(d); 
} 

在這裏,你只需要使用boost::any爲標準型對於任何和所有這樣的構造。總是投到任何東西,並始終包裹任何。然後,如果有人搞砸了,併發送錯誤的數據類型,你會得到異常,而不是未定義的行爲。

使用這樣的:

auto fun = std::function<double(double)>{[](double d) { return d; }}; 
register_callback(&wrap_legacy, &fun); 

還是安全的版本: 汽車任何=提振:: {任何的std ::函數{[(雙d){回報d; }}}; register_callback(& wrap_legacy,& fun);

當然,一般來說,client_data生存期要求指向堆分配,因此您需要處理該問題。還有更多的包裝可以做,例如包裝register_callback - 可以提高安全性。

+0

感謝和一個+1形成了我。上面的解決方案從您的第一個建議中得到了很大啓發。我沒有完全得到第二個,或者對我來說看起來太麻煩,因爲我不得不將整個算法放到這些花括號中,這些花括號本身就是一個函數參數。 – Steve06 2014-11-03 16:37:53

+0

您對包裝std:function的解決方案非常有趣,但是對具有多個參數的自己的函數my_func_to_be_input進行轉發的確切位置是否會進入?也可以將這樣一個wrap_legacy包裝泛化爲適用於各種(a)遺留函數(如register_callback)和(b)具有多個參數的客戶端函數(如我的my_func_to_be_input)? – Steve06 2014-11-11 21:15:42