首页 文章

不指定参数的调用方法

提问于
浏览
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 * 's that point to the data that can be passed to the internally called method. I'数组,我不确定这是否是解决此问题的最佳方法 .

我正在编写一个脚本系统,实质上可以从脚本中调用方法 . 因此,这些方法存储在查找表中,其中每个方法都有一个字符串名称,并且对于要调用的实际方法具有void * . 在执行时我知道方法需要多少参数以及参数是什么类型(当在查找表中给出方法时,类型被存储为元数据) . 这允许我将作为脚本中的参数的字符串值转换为它们实际应该的值(使用自定义转换系统) . 但转换器返回void *,因为你这样称它:

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

我可以保证 result 中存储的值实际上是所请求类型的值(如果存在此类型对的转换器),但无法转换为此类型,因为类型名称仅作为字符串提供 . 这使得转换器具有灵活性,并且真正无关紧要 . 但它使处理它返回的值变得复杂 . 所以在脚本中我会像这样打个电话:

MyMethod( 111, 222 )

然后解析它,方法名称将用于查找方法地址,然后转换器将它找到的值转换为预期的数据类型,但将它们返回为 void* . 然后调用Caller,传入方法地址,它已经转换的参数,一个字节数组,以及参数数据数组的大小,以字节为单位 . 在这一点上,我需要调用该方法并传递这些参数 . 同样,我无法修改它调用的现有方法 .

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

请不要暗示模棱两可;如果您需要更多上下文,我可以提供它 . 只是评论 . 对此,我真的非常感激 .

1 回答

  • 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中调用 .

    如果您有任何疑问,请告诉我 .

相关问题