2013-12-11 85 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。所以谢谢。我会让你知道它是如何工作的。 –