[英]map of pointers to functions of different return types and signatures
我正在尋找一種通過字符串輸入來調用不同函數的方法。
我有一個映射,該映射將每個唯一的字符串與一個函數指針聯系在一起,並具有一個查找函數來搜索該映射並返回一個指針(如果找到)。
現在的訣竅是,我需要一種方法來存儲和返回指向至少具有不同返回類型(如果可能)以及具有不同簽名的函數的指針。
用法是:
從網絡套接字獲取字符串輸入->查找並執行找到的功能->將結果直接推回套接字以進行序列化和發送,而不在乎實際發生的情況。
這可行嗎? 如果沒有,一個人將如何完成這項任務?
可以用一些不同的樣板代碼來完成。 如果簽名的數量足夠少,則可以容納多個函數指針向量(每種函數類型一個),然后容納一個映射,該映射將函數名稱與類型標識符(用於選擇向量)以及向量在向量中的位置進行映射。
第二種選擇是存儲boost::variant
(同樣,如果簽名集很小)。 您將需要提供一個訪問者對象,該對象可以評估功能(針對存儲的每種功能類型)並產生結果。 該類型由boost::variant
類型管理,因此不需要將類型標簽存儲在映射中。
您也可以使用完全類型擦除並將標記確定要調用的函數的類型以及boost::any
存儲函數指針的對象存儲在映射中。 您可以使用類型信息來檢索指針並執行功能,但是必須根據功能類型手動處理switch
。
另一方面,最簡單的方法是編寫具有固定接口的適配器。 然后,只需將指向適配器的指針存儲在映射中即可。
雖然不能存儲不同的函數指針,但是可以存儲包含這些函數的對象。
#include <iostream>
#include <cmath>
#include <map>
#include <string>
using namespace std;
class Functor{
public:
template<class T>
void operator()(T data){}
};
template<class T>
class BaseFunctor : public Functor{
public:
virtual void CallFunction(T data){ }
};
class FunctionPointer1 : public BaseFunctor<void *>{
public:
void doFunction1(){
cout << "Do Function 1"<<endl;
}
template<class T>
void CallFunction(T data){ doFunction1(); }
template<class T>
void operator()(T data){ this->CallFunction(data); }
};
class FunctionPointer2 : public BaseFunctor<int>{
public:
void doFunction2(int variable){ cout << "Do function 2 with integer variable" << variable <<endl; }
template<class T>
void CallFunction(T data) { doFunction2(data);}
template<class T>
void operator()(T data){ this->CallFunction(data); }
};
class FunctionPerformer{
private:
map<string,Functor> functions;
public:
FunctionPerformer(){
//init your map.
FunctionPointer1 function1;
FunctionPointer2 function2;
//-- follows
functions["Function1"] = function1;
functions["Functions2"] = function2;
//-- follows
}
Functor getFunctionFromString(string str){
return functions[str]
}
};
int main(int argc, char *argv[])
{
map<string,Functor> functions;
FunctionPerformer performer;
Functor func1, func2; // to hold return values from perfomer()
FunctionPointer1 *fn1; // to casting and execute the functions
FunctionPointer2 *fn2; // to casting and execute the functions
func1 = performer.getFunctionFromString("Function1");//get data
func2 = performer.getFunctionFromString("Function2");
//following two lines to cast the object and run the methods
fn1 = reinterpret_cast<FunctionPointer1 *>(&func1);
(*fn1)(NULL);
//following two lines to cast the object and run the methods
fn2 = reinterpret_cast<FunctionPointer2 *>(&func2);
(*fn2)(10);
system("Pause");
return 0;
}
我認為編輯部分使內容更清晰嗎? 該代碼可以進行一些優化。 玩吧。
不,這實際上是不可行的,如果您想執行此類操作,則需要一種真正的解釋語言。 一旦簽名不是恆定的,那么您需要做更多的事情。
如何使所有這些功能具有相同的簽名? 您可以使所有返回類型都實現一個接口,或者使用集合,類,聯合或結構。 參數相同。
您不能使用專業化和模板來解決此問題嗎?
template <class T>
T FooBar(void * params);
template<> int FooBar<int>( void * params );
template<> char FooBar<char>( void * params );
可以存儲適配器以消除不匹配,而不是存儲彼此之間太不同而無法容納在同一數據結構中的函數指針本身。 這是一種類型擦除的形式。 一個例子:
// Imaginary important resources
blaz_type get_blaz();
qux_type get_qux();
// The functions we'd like to put in our map
int foo(blaz_type);
std::string bar(qux_type);
using context_type = std::tuple<blaz_type, qux_type>;
using callback_type = std::function<void(context_type, socket_type&)>;
using std::get;
std::map<std::string, callback_type> callbacks = {
{
"foo"
, [](context_type context, socket_type& out)
{ marshall(out, foo(get<0>(std::move(context)))); }
}
, {
"bar"
, [](context_type context, socket_type& out)
{ marshall(out, bar(get<1>(std::move(context)))); }
}
};
在此示例中,適配器不是有狀態的,因此您實際上可以將void (*)(context_type, socket_type&)
用作callback_type
。
請注意,這種設計有點脆弱,因為context_type
需要了解存儲的回調可能需要的每種參數。 如果稍后需要存儲需要新類型參數的回調,則需要修改context_type
-如果改進了上述設計, 不要使用像0
和1
這樣的幻數作為std::get
參數為自己省去一些麻煩(特別是在從context_type
中刪除類型的相反情況下)。 如果所有回調都使用相同的參數,這不是問題,在這種情況下,您可以完全省去context_type
並將這些參數直接傳遞給回調。
關於LWS的示范 。
這在帶有可變參數模板的C ++ 11中是可行的。 在https://stackoverflow.com/a/33837343/1496826中查看我的答案
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.