无指定参数的调用方法 [英] Call Method Without Specifying Parameters

查看:138
本文介绍了无指定参数的调用方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是很难解释,但我会尽我所能。我会提出这个问题,因为它适用于一个方法,但是知道这个解决方案应该是通用的,适用于任何可能的方法。请考虑以下内容:

this is sort of difficult to explain but I'll do my best. I will pose the question as it applies to one method, but know that this solution should be generic enough to apply to any possible method given. Consider the following:

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

I have a regular old global method:

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

我有另一个方法来调用此方法。

I have another method that is to call this method.

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

调用者应该能够在内部调用任何方法,而不必知道它需要多少参数以及它们的数据类型。所有它真正了解的方法是方法的地址和整个参数列表的大小,以字节为单位。

This caller should be able to call any method internally without knowing how many parameters it takes and what their data types are. All it really knows about the method is the address to the method and the size, in bytes, of the entire parameter list.

简单地说,如何调用

基本上,不修改 MyMethod ,如何将 void * data 推入用作 Caller 中的参数的寄存器?这可能吗?

Essentially, without modifying MyMethod, how do I push the void* data into the registers used as parameters from within Caller? Is this possible? I'm not concerned about safety or portability.

在调用 Caller 之前,我有一个void *指向可以传递到内部调用方法的数据。我不知道这是否是这个问题的最佳方法。

Before Caller is called, I have an array of void*'s that point to the data that can be passed to the internally called method. I'm not sure if this is even the best approach to this problem.

我写一个脚本系统,本质上,可以从脚本调用方法。因此,方法存储在查找表中,其中每个都有一个字符串名称,并有一个void *到实际的方法被调用。在执行时,我知道方法期望的参数和参数是什么类型(当方法在查找表中给出条目时,类型被存储为元数据)。这允许我将作为脚本中的参数的字符串值转换为他们实际应该使用的值(使用自定义转换系统)。但转换器返回一个void *,因为你这样调用:

I'm writing a scripting system, in essence, that can call methods from the script. So the methods are stored in a lookup table, where each is given a string name, and have a void* to the actual method to be called. At execution time I know how many parameters the method expects and what types the parameters are (the types are stored as metadata when the method is given an entry in the lookup table). This allows me to convert the string values that are the parameters in the script to the values they actually should be (using a custom conversion system). But the converter returns a void*, because you call it as such:

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

我可以保证存储在结果实际上是请求的类型(如果存在这种类型对的转换器),但是没有办法转换为这种类型,因为类型名称只是作为字符串提供。这使得转换器灵活,真正类型无关。但是它使得处理返回的值变得复杂。所以在脚本中我会这样调用:

I can guarantee that the value stored in result is actually of the requested type (if a converter for this type-pair exists), but have no way of casting to this type, as the type name is merely provided as a string. This makes the converter flexible and really type-indifferent. But it makes handling the values that it returns complicated. So in script I would make a call like this:

MyMethod( 111, 222 )

然后将被解析,方法名将用于查找方法地址,然后转换器将其找到的值转换为预期的数据类型,但返回它们 void * 。然后调用Caller,传入方法地址,它转换的参数,作为一个字节数组,以及参数数据数组的大小(以字节为单位)。正是在这一点上,我需要调用该方法并传递这些参数。再次,我不能修改它所调用的现有方法。

This would then be parsed, the method name would be used to look up the method address, and the converter would then convert the values it finds into the expected datatypes, but return them as void*. Then a call to Caller would be made, passing in the method address, arguments it has converted, as an array of bytes, and the size of the array of parameter data, in bytes. It is at this point that I need to call that method and pass these parameters. Again, I cannot modify the existing methods it is calling.

我已经查看了程序集来传递这些数据,但是似乎你必须使方法裸体读取参数直接在汇编或做别的事情,我从来没有真正工作在汇编以前。虽然如果解决方案在于装配,我很高兴学习一些。

I've looked into assembly to pass this data in, but it seems that you have to either make the method naked to read parameters directly in assembly or do something else, and I've never really worked in assembly before. Although if the solution lies in assembly, I'm fine with learning some.

请不要downvote的歧义;如果你需要更多的上下文我可以提供它。只是评论。

Please don't downvote for ambiguity; if you need more context I can provide it. Just comment. I really appreciate it.

推荐答案

稍微更改实现细节,这里是如何做你想做的

Changing the implementation details slightly, here is how to do what you want

#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的向量,并将任意值放入向量。

Note as presented here, this only works with global functions with a void return type. This solution also uses boost::any which can store any type, and from which you can extract the type later. Thus to use it register your functions. Then created a vector of boost::any and put in your arbitrary values into the vector. Then look up the function name and call like in the example main.

如果您有任何问题,请告诉我们。

Let me know if you have any questions.

这篇关于无指定参数的调用方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆