2017-01-09 12 views
1

Dies ist möglicherweise der falsche Titel, aber ich weiß nicht, wie es sonst zu beschreiben. Was ich versuche, ist eine C++ Funktion aus meiner Skriptsprache aufzurufen (läuft in einer VM). Ich habe ein paar Probleme damit herausgefunden, wie man Parameter an die Funktion weitergibt.Dynamische C++ Funktion Parameter

Meine beste Lösung so weit ist, dies zu tun:

void func(int a) { 

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

// Code 

} 

Dann wird die Funktion aufzurufen ich es zuerst an die VM aussetzen, die Parameter, um es zu geben. Dies ist ein verkürzter Code, aber alles wird in ein void (*) umgewandelt, so dass es in einer Hash-Tabelle gespeichert werden kann.

EXPOSE greift einen Zeiger auf den Funktionstest und speichert, dass es einen einzelnen in aufgerufen werden muss. Es speichert den Zeiger als void (*)() in einer Hash-Tabelle, so dass, wenn ich es aufrufen möchte, ich einen Anruf von der VM machen kann und es aufgelöst wird. Dann kopiert der Code innerhalb der Funktion (die ich aus einem Makro in der Frage erweitert habe) die Parameter, die vom Aufruf an die VM übergeben wurden, an die Parameter der Funktion.

Dies funktioniert, aber es ist nicht die eleganteste Lösung, vor allem, weil ich ein Makro für jede Funktion aufrufen muss, die ich für das Scripting verfügbar machen möchte. Gibt es eine bessere Lösung? Vielen Dank.

+0

Ihr Teil unter "Dann tue ich" hat keine Verbindung zum obigen Teil. Es ist schwer, wirklich genug zu verstehen, um zu helfen. – AndyG

+0

@AndyG Ich entschuldige mich, hoffentlich die Bearbeitung löscht es – BlueSpud

+0

Nicht ganz. Was ist das Makro "EXPOSE"? Was ist 'cppFunktion'? Was ist der Punkt von "void (* ptr)() = (void (*)());'? – AndyG

Antwort

2

Sie können auch genau das verwenden, was C++ zu bieten hat. Hier ist ein kleines Beispiel, das ich zusammen geworfen habe.

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); 
} 

Jetzt können Sie eine Karte von script2cxx (smart) Zeiger bauen und sie mit Vektoren Ihrer Script-Objekte aufrufen.

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 

Und nennen sie:

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

Keine unsicheren Würfe und/oder void-Zeiger wurden bei der Herstellung dieses Beispiel geschadet.

+0

Ich habe noch nie die Ellipse für Vorlagen verwendet, großartige Lösung! Vielen Dank – BlueSpud

Verwandte Themen