2017-01-09 11 views
1

これはおそらく間違ったタイトルですが、それ以外の記述方法はわかりません。私がやろうとしているのは、スクリプト言語(VMで動作)からC++関数を呼び出すことです。私は関数にパラメータを渡す方法を理解するのにいくつかの問題に遭遇しました。それにパラメータを与えて、私は最初のVMにそれを公開する機能を呼び出すために、そして、動的なC++関数のパラメータ

void func(int a) { 

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

// Code 

} 

私の最善の解決策は、これまでのところ、これを行うことです。これは短縮されたコードですが、すべてがvoid(*)にキャストされるため、ハッシュテーブルに格納できます。

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

EXPOSE grabは、機能テストへのポインタであり、単一の呼び出しが必要であることを格納します。ハッシュテーブルにvoid(*)()としてポインタを格納するので、呼び出すときにVMから呼び出して解決できます。次に、関数内のコード(質問のマクロから展開したもの)は、呼び出しからVMに渡されたパラメータを関数のパラメータにコピーします。

これはうまくいきますが、これは最も洗練された解決策ではありません。特に、スクリプト作成のために公開したい機能ごとにマクロを呼び出す必要があるからです。より良い解決策はありますか?ありがとう。

+0

"Then I do"の下にある部分は、実際に上記の部分に接続していません。本当に理解するのは難しいです。 – 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

関連する問題