2013-12-11 128 views
0

這是很難解釋的,但我會盡我所能。我將提出這個問題,因爲它適用於一種方法,但知道這個解決方案應該足夠通用,以適用於任何可能的方法。考慮以下幾點:不指定參數的呼叫方法

我有一個普通的舊全局方法:

void MyMethod(int a, int b) 
{ 
    cout << a << " , " << b << endl; 
} 

我有另一種方法是調用此方法。

void Caller(void* method, void* data, int size) 
{ 
    // convert method to some function calling convention 
    // call the method here with the given data 
} 

該來電者應該能夠在內部調用任何方法不知道它的許多參數需要,以及他們的數據類型。它真正知道的方法是整個參數列表的方法地址和字節大小。

簡而言之,我如何調用任意方法並將其傳遞給任意數量的數據,以便將其解釋爲參數?

本質上,在不修改MyMethod的情況下,如何將void* data推入用作Caller中參數的寄存器?這可能嗎?我不關心安全性或便攜性。

在調用Caller之前,我有一個void *數組指向可以傳遞給內部調用方法的數據。我不確定這是否是解決此問題的最佳方法。

我正在編寫一個腳本系統,實質上它可以從腳本調用方法。所以這些方法被存儲在一個查找表中,每個查詢表都被賦予一個字符串名稱,並且具有一個void *給要調用的實際方法。在執行時,我知道該方法需要多少個參數以及參數是什麼類型(當查詢表中給出該方法時,這些類型將作爲元數據存儲)。這允許我將腳本中參數的字符串值轉換爲實際應該使用的值(使用自定義轉換系統)。但是,轉換器返回一個void *,因爲你把它作爲這樣:

string s = "123456"; 
void* result = Converter::Convert("string*", "int", &s); 

我可以保證存儲在result值實際上是請求的類型(如果這種類型的配對轉換器存在),但沒有辦法轉換爲這種類型,因爲類型名稱僅作爲字符串提供。這使轉換器變得靈活並且非常無關緊要。但它使得處理它變得複雜的價值。所以在劇本我會做這樣的呼籲:

MyMethod(111, 222) 

這將被解析,方法名稱將被用於查找該方法的地址,然後轉換器將其轉換髮現注入預期值數據類型,但將它們返回爲void*。然後,調用者將被調用,傳入方法地址,轉換的參數,字節數組和參數數據數組的大小(以字節爲單位)。在這一點上,我需要調用該方法並傳遞這些參數。再次,我無法修改它正在調用的現有方法。

我已經看着程序集來傳遞這些數據,但它似乎必須使該方法裸露直接在程序集中讀取參數或執行其他操作,而且我從來沒有真正在程序集中工作過。雖然如果解決方案在於組裝,我很好學習一些。

請不要低估歧義;如果你需要更多的上下文,我可以提供。只是評論。對此,我真的非常感激。

+0

你可以使用C++ 11嗎? –

+0

是的,很抱歉沒有標記爲此。 –

+0

你知道有關'std :: function'和'std :: bind'的任何信息嗎? – Constructor

回答

1

更改實施細節咯,這裏是如何做你想做的

#include <iostream> 
#include <boost/any.hpp> 
#include <vector> 
#include <functional> 
#include <map> 
#include <string> 

using namespace std; 


template<class F> 
struct ConstructCaller{}; 

template<class T, int i> 
struct TypeAndInt 
{ 
    enum{idx = i}; 
    typedef T type; 
}; 

template<class... T> 
struct TypeList{}; 

template<class A, class B> 
struct CombineTypeList{}; 

template<class... T1, class... T2> 
struct CombineTypeList<TypeList<T1...>, TypeList<T2...>> 
{ 
    typedef TypeList<T1..., T2...> type; 
}; 

template<int idx, class... T> 
struct ToTypeAndIntList{ 

}; 
template<int idx,class T0, class T1, class... T> 
struct ToTypeAndIntList<idx, T0,T1,T...>{ 
    typedef typename CombineTypeList<TypeList<TypeAndInt<T0, idx> >, typename ToTypeAndIntList<idx+1,T1,T...>::type>::type type; 
}; 

template<int idx, class T0> 
struct ToTypeAndIntList<idx,T0>{ 
    typedef TypeList < TypeAndInt<T0, idx> > type; 
}; 
template<class... P> 
struct ConstructCaller<void(*)(P...)> 
{ 
    typedef void(*FuncType)(P...); 
    FuncType f_; 
    template<class T> 
    typename T::type Get(const vector<boost::any>& vec){ 
    return boost::any_cast<typename T::type>(vec.at(T::idx)); 
    } 
    template<class... TI> 
    void DoCall(TypeList<TI...>, const vector<boost::any>& vec){ 
    return f_(Get<TI>(vec)...); 
    } 

    void operator()(const vector<boost::any>& vec){ 
    typedef typename ToTypeAndIntList<0, P...>::type List_t; 
    return DoCall(List_t{}, vec); 
    } 

}; 


std::map < std::string, std::function<void(const std::vector<boost::any>&)>> func_map; 

template<class F> 
void RegisterFunction(std::string name, F f){ 
    ConstructCaller<F> c; 
    c.f_ = f; 
    func_map[name] = c; 
} 
void MyMethod(int a, int b) 
{ 
    cout << a << " , " << b << endl; 
} 
void MyMethod2(std::string a, int b) 
{ 
    cout << a << " , " << b << endl; 
} 
int main(){ 
    RegisterFunction("MyMethod", &MyMethod); 
    RegisterFunction("MyMethod2", &MyMethod2); 

    std::vector<boost::any> vec; 
    vec.push_back(1); 
    vec.push_back(2); 
    func_map["MyMethod"](vec); 

    vec.clear(); 
    vec.push_back(std::string("Hello World")); 
    vec.push_back(2); 
    func_map["MyMethod2"](vec); 

} 

注意這裏所提出,這只是與返回類型爲void全球職能工作。 該解決方案還使用了boost :: any,它可以存儲任何類型,以後可以從中提取類型。因此使用它註冊你的功能。然後創建一個boost :: any向量,並將您的任意值放入向量中。然後在示例main中查找函數名稱和調用。

讓我知道如果您有任何問題。

+0

當我回到我的機器時,我會稍後檢查您的解決方案。我需要遠離Boost/STL,但我們確實有一個內部變體來反映boost :: any。所以謝謝。我會讓你知道它是如何工作的。 –