不指定参数的调用方法

时间:2013-12-11 19:20:28

标签: c++ pointers c++11 methods

这有点难以解释,但我会尽我所能。我将提出问题,因为它适用于一种方法,但要知道这个解决方案应该足够通用,以适用于给定的任何可能的方法。请考虑以下事项:

我有一个常规的旧全局方法:

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*。然后调用Caller,传入方法地址,它已经转换的参数,一个字节数组,以及参数数据数组的大小,以字节为单位。在这一点上,我需要调用该方法并传递这些参数。同样,我无法修改它正在调用的现有方法。

我已经研究过汇编来传递这些数据,但是你似乎必须让方法裸以直接在汇编中读取参数或者做其他事情,而且我以前从未在汇编中工作过。虽然如果解决方案在于装配,我可以学习一些。

请不要因为含糊不清而贬低;如果您需要更多上下文,我可以提供它。只是评论。我真的很感激。

1 个答案:

答案 0 :(得分: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。

如果您有任何问题,请与我们联系。