2017-01-09 134 views
1

這很可能是錯誤的標題,但我不知道如何描述它。我想要做的是從我的腳本語言(運行在虛擬機中)調用C++函數。我遇到了一些麻煩,想知道如何將參數傳遞給函數。動態C++函數參數

我最好的解決辦法,到目前爲止是這樣做:

void func(int a) { 

// Start param copy 
char c; 
char* par_start = &c - sizeof(char) - getCurrentFuncParamOffset(); 
copyCurrentParams(par_start); 
// End copy 

// Code 

} 

然後,調用函數我第一次把它暴露在VM,將參數給它。這是一些縮短的代碼,但所有內容都被轉換爲void(*),以便將其存儲在散列表中。

EXPOSE(test, int); 
vm.call("test", 12) 

EXPOSE抓取指向函數測試的指針,並存儲它需要單個進入的地方。它將指針作爲void(*)()存儲在散列表中,以便當我想調用它時,我可以從VM撥打電話並解析它。然後,函數內部的代碼(我從問題中的宏中擴展而來)會將從調用傳遞給虛擬機的參數複製到函數的參數中。

這可行,但它不是最優雅的解決方案,尤其是因爲我將不得不爲每個我想爲腳本公開的函數調用宏。有更好的解決方案嗎?謝謝。

+0

您在「然後我做」下的部分與上述部分沒有任何關聯。真的很難理解足夠的幫助。 – AndyG

+0

@AndyG我很抱歉,希望編輯清除它 – BlueSpud

+0

不完全。什麼是EXPOSE宏?什麼是「cppFunction」? void(* ptr)()=(void(*)());'? – AndyG

回答

2

你可以使用C++所提供的。這是我扔在一起的一個小例子。現在

class ScriptObj {}; // Your type that encapsulates script objects. 
        // May be as simple as an integer or a string, 
        // or arbitrarily complex like PyObj 

template <typename T> T from_script(ScriptObj); // conversion to and from 
template <typename T> ScriptObj to_script(T); // C++ types. You provide 
               // specialized implementations. 
               // Bad conversions should throw. 

// Abstract base class for C++ functions callable from the scripts. 
// The scripting engine should pass a vector of parameters and a pointer to result. 
struct script2cxx 
{ 
    virtual ~script2cxx() {} 
    virtual ScriptObj operator()(const std::vector<ScriptObj>& params) = 0; 
};  


// Concrete class that exposes a C++ function to the script engine. 
template <class Res, class ... Param> 
struct script2cxx_impl : script2cxx 
{ 

    using funcType = Res(*)(Param...); 

    virtual ScriptObj operator()(const std::vector<ScriptObj>& params) 
    { 
     if (sizeof...(Param) != params.size()) 
      throw std::domain_error("Invalid size of parameter array"); 
     return to_script<Res>(call_impl<std::tuple<Param...>>(func, params, std::make_index_sequence<sizeof...(Param)>())); 
    } 

    template <class Tuple, std::size_t... N> 
     Res call_impl(funcType func, const std::vector<ScriptObj>& params, std::index_sequence<N...>) 
     { 
      return func(from_script<typename std::tuple_element<N, Tuple>::type>(params[N])...); 
     }; 

    funcType func; 

    script2cxx_impl(funcType func) : func(func) {} 
}; 

// a helper biold function 
template <class Res, class ... Param> 
auto expose(Res(*func)(Param...)) { 
    return new script2cxx_impl<Res, Param...>(func); 
} 

,你可以在地圖上標註的script2cxx(智能)指針,並與你的腳本對象的載體給他們打電話。

std::map<std::string, std::unique_ptr<script2cxx>> exposed; 


int foo(double, char[], int**) {...} 

// below is the only line you need to add 
// if you want to expose any standalone C++ function. 
// no boilerplate. 

exposed["foo"]=expose(foo); // you can wrap this in a macro if you want 

,並呼籲他們:

std::vector<ScriptObj> somevector = ...; 
std::string somestring = ...; 
(*exposed[somestring])(somevector); 

沒有不安全的鑄件和/或空指針在做這個例子中受到傷害。

+0

我以前從來沒有使用模板的省略號,很好的解決方案!謝謝 – BlueSpud