• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
SiCrane

More AngelScript binding wrappers

28 posts in this topic

As I apparently do fairly frequently, I was thinking about AngelScript binding again. One of the annoyances of using the current autowrapper add-on is that to create a generic wrapper you need two steps: to define the proxy function and then register it, and since the proxy has to be declared at namespace scope, this separates registration into two different places. By using function pointers as non-type template arguments to the proxy functions, I've come up with a way to simplify that. Basically any function you would normally register with asFUNCTION() and asCALL_CDECL you can register with WRAP_FN() instead of asFUNCTION(). Ex:
[code]
if (use_generic) {
r = engine->RegisterGlobalFunction("void print(string & in)", WRAP_FN(print), asCALL_GENERIC); assert(r >= 0);
} else {
r = engine->RegisterGlobalFunction("void print(string & in)", asFUNCTION(print), asCALL_CDECL); assert(r >= 0);
}
[/code]
Similarly WRAP_MFN() can be used instead of asMETHOD() and asCALL_THISCALL, WRAP_OBJ_FIRST() instead of asCALL_CDECL_OBJFIRST and WRAP_OBJ_LAST() instead of asCALL_CDECL_OBJLAST. There are also PR versions of the macros for overloads. (The PR macros are actually more straightforward than the regular ones; the mechanism I originally wanted for the non-PR macros ended up crashing MSVC 2010.)

The one major limitation with this is the variable parameter type, e.g.: (?&in). Since AngelScript passes variable parameters to generic and non-generic functions in fundamentally different ways, I can't think of a reasonable mechanism to map one to the other.

While I was at it, I also worked on automatic wrappers for use with smart pointers as value types. This includes creating getters and setters as well as functions to automatically invoke member functions. They can be used to generate either generic or native functions.

An example file demonstrating both at work:
[code]
#include "angelscript.h"
#include "scriptstdstring.h"

#include "as_smart_ptr_wrapper.h"
#include "as_gen_wrapper.h"

#include <iostream>
#include <cassert>
#include <cstdio>

#include <memory>

// Types to export

struct Base {
virtual ~Base() {}

void moo(void) const { std::cout << "Moo." << std::endl; }
};

struct Derived : Base {
int x;
int y;

void moo(void) const { std::cout << "Moo!" << std::endl; }
void add(int value) { x += value; y += value; }

int & getter(void) { return x; }
};

typedef std::shared_ptr<Base> BasePtr;
typedef std::shared_ptr<Derived> DerivedPtr;

// Helper functions

template <typename T>
void construct(void * address) {
new (address) T;
}

template <typename T>
void destroy(T * object) {
object->~T();
}

template <typename T>
void copy_construct(void * address, T * other) {
new (address) T(*other);
}

template <typename T>
void assign(T * lhs, T* rhs) {
*lhs = *rhs;
}

void MessageCallback(const asSMessageInfo *msg, void *param)
{
const char *type = "ERR ";
if (msg->type == asMSGTYPE_WARNING) {
type = "WARN";
} else if (msg->type == asMSGTYPE_INFORMATION) {
type = "INFO";
}

printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}

void __cdecl print(const std::string & str) {
std::cout << str;
}

template <typename T>
T foo(T);

int main(int, char **) {
asIScriptEngine * engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
RegisterStdString(engine);

bool use_generic = strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY");

int r;
if (use_generic) {
r = engine->RegisterGlobalFunction("void print(string & in)", WRAP_FN(print), asCALL_GENERIC); assert(r >= 0);
} else {
r = engine->RegisterGlobalFunction("void print(string & in)", asFUNCTION(print), asCALL_CDECL); assert(r >= 0);
}

// Base
r = engine->RegisterObjectType("Base", sizeof(BasePtr), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert(r >= 0);
if (use_generic) {
r = engine->RegisterObjectBehaviour("Base", asBEHAVE_CONSTRUCT, "void f()", WRAP_OBJ_FIRST(construct<BasePtr>), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Base", asBEHAVE_CONSTRUCT, "void f(const Base & in)", WRAP_OBJ_FIRST(copy_construct<BasePtr>), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Base", asBEHAVE_DESTRUCT, "void f()", WRAP_OBJ_FIRST(destroy<BasePtr>), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("Base", "Base &opAssign(const Base &in)", WRAP_OBJ_FIRST(assign<BasePtr>), asCALL_GENERIC); assert(r >= 0);

r = engine->RegisterObjectMethod("Base", "void moo(void) const", GEN_CALLER(Base, moo), asCALL_GENERIC); assert(r >= 0);
} else {
r = engine->RegisterObjectBehaviour("Base", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(construct<BasePtr>), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Base", asBEHAVE_CONSTRUCT, "void f(const Base & in)", asFUNCTION(copy_construct<BasePtr>), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Base", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(destroy<BasePtr>), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectMethod("Base", "Base &opAssign(const Base &in)", asFUNCTION(assign<BasePtr>), asCALL_CDECL_OBJFIRST); assert(r >= 0);

r = engine->RegisterObjectMethod("Base", "void moo(void) const", CALLER(Base, moo), asCALL_CDECL_OBJFIRST); assert(r >= 0);
}

// Derived
r = engine->RegisterObjectType("Derived", sizeof(DerivedPtr), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert(r >= 0);
if (use_generic) {
r = engine->RegisterObjectBehaviour("Derived", asBEHAVE_CONSTRUCT, "void f()", WRAP_OBJ_FIRST(construct<DerivedPtr>), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Derived", asBEHAVE_CONSTRUCT, "void f(const Derived & in)", WRAP_OBJ_FIRST(copy_construct<DerivedPtr>), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Derived", asBEHAVE_DESTRUCT, "void f()", WRAP_OBJ_FIRST(destroy<DerivedPtr>), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "Derived &opAssign(const Derived & in)", WRAP_OBJ_FIRST(assign<DerivedPtr>), asCALL_GENERIC); assert(r >= 0);

r = engine->RegisterObjectMethod("Derived", "const int & get_x() const", REF_GETTER_GEN(Derived, x), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "void set_x(const int & in)", REF_SETTER_GEN(Derived, x), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "int get_y() const", GETTER_GEN(Derived, y), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "void set_y(int)", SETTER_GEN(Derived, y), asCALL_GENERIC); assert(r >= 0);

r = engine->RegisterObjectMethod("Derived", "void moo(void) const", GEN_CALLER(Derived, moo), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "void add(int)", GEN_CALLER(Derived, add), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "int & getter(void)", GEN_CALLER(Derived, getter), asCALL_GENERIC); assert(r >= 0);
} else {
r = engine->RegisterObjectBehaviour("Derived", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(construct<DerivedPtr>), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Derived", asBEHAVE_CONSTRUCT, "void f(const Derived & in)", asFUNCTION(copy_construct<DerivedPtr>), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Derived", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(destroy<DerivedPtr>), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "Derived &opAssign(const Derived & in)", asFUNCTION(assign<DerivedPtr>), asCALL_CDECL_OBJFIRST); assert(r >= 0);

r = engine->RegisterObjectMethod("Derived", "const int & get_x() const", REF_GETTER(Derived, x), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "void set_x(const int & in)", REF_SETTER(Derived, x), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "int get_y() const", GETTER(Derived, y), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "void set_y(int)", SETTER(Derived, y), asCALL_CDECL_OBJFIRST); assert(r >= 0);

r = engine->RegisterObjectMethod("Derived", "void moo(void) const", CALLER(Derived, moo), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "void add(int)", CALLER(Derived, add), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectMethod("Derived", "int & getter(void)", CALLER(Derived, getter), asCALL_CDECL_OBJFIRST); assert(r >= 0);
}

// conversions
if (use_generic) {
r = engine->RegisterObjectBehaviour("Base", asBEHAVE_VALUE_CAST, "Derived f() const", WRAP_OBJ_FIRST((std::dynamic_pointer_cast<Derived, Base>)), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Derived", asBEHAVE_IMPLICIT_VALUE_CAST, "Base f() const", WRAP_OBJ_FIRST((std::static_pointer_cast<Base, Derived>)), asCALL_GENERIC); assert(r >= 0);
} else {
r = engine->RegisterObjectBehaviour("Base", asBEHAVE_VALUE_CAST, "Derived f() const", asFUNCTION((std::dynamic_pointer_cast<Derived, Base>)), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectBehaviour("Derived", asBEHAVE_IMPLICIT_VALUE_CAST, "Base f() const", asFUNCTION((std::static_pointer_cast<Base, Derived>)), asCALL_CDECL_OBJFIRST); assert(r >= 0);
}

const char script[] =
"void foo(const Base & in ptr) {\n"
" ptr.moo();\n"
" Derived d = Derived(ptr);\n"
" print(d.x + \"\\n\");\n"
" print(d.y + \"\\n\");\n"
" d.getter() = 3;\n"
" d.y = 4;\n"
" d.moo();\n"
" d.add(1);\n"
"}\n"
;

asIScriptModule * mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
r = mod->AddScriptSection("script", script, sizeof(script) - 1); assert(r >= 0);
r = mod->Build(); assert(r >= 0);

int func_id = mod->GetFunctionIdByDecl("void foo(const Base & in)");

Derived * d = new Derived;
d->x = 1;
d->y = 2;
BasePtr base(d);


asIScriptContext * ctx = engine->CreateContext();
ctx->Prepare(func_id);
ctx->SetArgObject(0, &base);
ctx->Execute();

ctx->Release();

engine->Release();

std::cout << d->x << std::endl;
std::cout << d->y << std::endl;
}
[/code]
A header for the generic wrappers good for up to four arguments:
[code]
#ifndef AS_GEN_WRAPPER_H
#define AS_GEN_WRAPPER_H

#include "angelscript.h"
#include <new>

namespace gw {

template <typename T> class Proxy {
public:
T value;
Proxy(T value) : value(value) {}
static T cast(void * ptr) {
return reinterpret_cast<Proxy<T> *>(&ptr)->value;
}
private:
Proxy(const Proxy &);
Proxy & operator=(const Proxy &);
};

template <typename T> struct Wrapper {};
template <typename T> struct ObjFirst {};
template <typename T> struct ObjLast {};

template <>
struct Wrapper<void (*)(void)> {
template <void (*fp)(void)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)());
}
};

template <typename R>
struct Wrapper<R (*)(void)> {
template <R (*fp)(void)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)());
}
};

template <typename T>
struct Wrapper<void (T::*)(void)> {
template <void (T::*fp)(void)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)());
}
};

template <typename T, typename R>
struct Wrapper<R (T::*)(void)> {
template <R (T::*fp)(void)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)());
}
};

template <typename T>
struct Wrapper<void (T::*)(void) const> {
template <void (T::*fp)(void) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)());
}
};

template <typename T, typename R>
struct Wrapper<R (T::*)(void) const> {
template <R (T::*fp)(void) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)());
}
};

template <typename T>
struct ObjFirst<void (*)(T)> {
template <void (*fp)(T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename T, typename R>
struct ObjFirst<R (*)(T)> {
template <R (*fp)(T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename T>
struct ObjLast<void (*)(T)> {
template <void (*fp)(T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename T, typename R>
struct ObjLast<R (*)(T)> {
template <R (*fp)(T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename A0>
struct Wrapper<void (*)(A0)> {
template <void (*fp)(A0)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
};

template <typename R, typename A0>
struct Wrapper<R (*)(A0)> {
template <R (*fp)(A0)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
};

template <typename T, typename A0>
struct Wrapper<void (T::*)(A0)> {
template <void (T::*fp)(A0)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
};

template <typename T, typename R, typename A0>
struct Wrapper<R (T::*)(A0)> {
template <R (T::*fp)(A0)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
};

template <typename T, typename A0>
struct Wrapper<void (T::*)(A0) const> {
template <void (T::*fp)(A0) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
};

template <typename T, typename R, typename A0>
struct Wrapper<R (T::*)(A0) const> {
template <R (T::*fp)(A0) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
};

template <typename T, typename A0>
struct ObjFirst<void (*)(T, A0)> {
template <void (*fp)(T, A0)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
Proxy<T>::cast(gen->GetObject()),
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
};

template <typename T, typename R, typename A0>
struct ObjFirst<R (*)(T, A0)> {
template <R (*fp)(T, A0)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
Proxy<T>::cast(gen->GetObject()),
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
};

template <typename T, typename A0>
struct ObjLast<void (*)(A0, T)> {
template <void (*fp)(A0, T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename T, typename R, typename A0>
struct ObjLast<R (*)(A0, T)> {
template <R (*fp)(A0, T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename A0, typename A1>
struct Wrapper<void (*)(A0, A1)> {
template <void (*fp)(A0, A1)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
};

template <typename R, typename A0, typename A1>
struct Wrapper<R (*)(A0, A1)> {
template <R (*fp)(A0, A1)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
};

template <typename T, typename A0, typename A1>
struct Wrapper<void (T::*)(A0, A1)> {
template <void (T::*fp)(A0, A1)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
};

template <typename T, typename R, typename A0, typename A1>
struct Wrapper<R (T::*)(A0, A1)> {
template <R (T::*fp)(A0, A1)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
};

template <typename T, typename A0, typename A1>
struct Wrapper<void (T::*)(A0, A1) const> {
template <void (T::*fp)(A0, A1) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
};

template <typename T, typename R, typename A0, typename A1>
struct Wrapper<R (T::*)(A0, A1) const> {
template <R (T::*fp)(A0, A1) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
};

template <typename T, typename A0, typename A1>
struct ObjFirst<void (*)(T, A0, A1)> {
template <void (*fp)(T, A0, A1)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
Proxy<T>::cast(gen->GetObject()),
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
};

template <typename T, typename R, typename A0, typename A1>
struct ObjFirst<R (*)(T, A0, A1)> {
template <R (*fp)(T, A0, A1)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
Proxy<T>::cast(gen->GetObject()),
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
};

template <typename T, typename A0, typename A1>
struct ObjLast<void (*)(A0, A1, T)> {
template <void (*fp)(A0, A1, T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename T, typename R, typename A0, typename A1>
struct ObjLast<R (*)(A0, A1, T)> {
template <R (*fp)(A0, A1, T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename A0, typename A1, typename A2>
struct Wrapper<void (*)(A0, A1, A2)> {
template <void (*fp)(A0, A1, A2)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
};

template <typename R, typename A0, typename A1, typename A2>
struct Wrapper<R (*)(A0, A1, A2)> {
template <R (*fp)(A0, A1, A2)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
};

template <typename T, typename A0, typename A1, typename A2>
struct Wrapper<void (T::*)(A0, A1, A2)> {
template <void (T::*fp)(A0, A1, A2)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
};

template <typename T, typename R, typename A0, typename A1, typename A2>
struct Wrapper<R (T::*)(A0, A1, A2)> {
template <R (T::*fp)(A0, A1, A2)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
};

template <typename T, typename A0, typename A1, typename A2>
struct Wrapper<void (T::*)(A0, A1, A2) const> {
template <void (T::*fp)(A0, A1, A2) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
};

template <typename T, typename R, typename A0, typename A1, typename A2>
struct Wrapper<R (T::*)(A0, A1, A2) const> {
template <R (T::*fp)(A0, A1, A2) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
};

template <typename T, typename A0, typename A1, typename A2>
struct ObjFirst<void (*)(T, A0, A1, A2)> {
template <void (*fp)(T, A0, A1, A2)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
Proxy<T>::cast(gen->GetObject()),
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
};

template <typename T, typename R, typename A0, typename A1, typename A2>
struct ObjFirst<R (*)(T, A0, A1, A2)> {
template <R (*fp)(T, A0, A1, A2)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
Proxy<T>::cast(gen->GetObject()),
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
};

template <typename T, typename A0, typename A1, typename A2>
struct ObjLast<void (*)(A0, A1, A2, T)> {
template <void (*fp)(A0, A1, A2, T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename T, typename R, typename A0, typename A1, typename A2>
struct ObjLast<R (*)(A0, A1, A2, T)> {
template <R (*fp)(A0, A1, A2, T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename A0, typename A1, typename A2, typename A3>
struct Wrapper<void (*)(A0, A1, A2, A3)> {
template <void (*fp)(A0, A1, A2, A3)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
};

template <typename R, typename A0, typename A1, typename A2, typename A3>
struct Wrapper<R (*)(A0, A1, A2, A3)> {
template <R (*fp)(A0, A1, A2, A3)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
};

template <typename T, typename A0, typename A1, typename A2, typename A3>
struct Wrapper<void (T::*)(A0, A1, A2, A3)> {
template <void (T::*fp)(A0, A1, A2, A3)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
};

template <typename T, typename R, typename A0, typename A1, typename A2, typename A3>
struct Wrapper<R (T::*)(A0, A1, A2, A3)> {
template <R (T::*fp)(A0, A1, A2, A3)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
};

template <typename T, typename A0, typename A1, typename A2, typename A3>
struct Wrapper<void (T::*)(A0, A1, A2, A3) const> {
template <void (T::*fp)(A0, A1, A2, A3) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
};

template <typename T, typename R, typename A0, typename A1, typename A2, typename A3>
struct Wrapper<R (T::*)(A0, A1, A2, A3) const> {
template <R (T::*fp)(A0, A1, A2, A3) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((static_cast<T *>(gen->GetObject())->*fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
};

template <typename T, typename A0, typename A1, typename A2, typename A3>
struct ObjFirst<void (*)(T, A0, A1, A2, A3)> {
template <void (*fp)(T, A0, A1, A2, A3)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
Proxy<T>::cast(gen->GetObject()),
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
};

template <typename T, typename R, typename A0, typename A1, typename A2, typename A3>
struct ObjFirst<R (*)(T, A0, A1, A2, A3)> {
template <R (*fp)(T, A0, A1, A2, A3)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
Proxy<T>::cast(gen->GetObject()),
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
};

template <typename T, typename A0, typename A1, typename A2, typename A3>
struct ObjLast<void (*)(A0, A1, A2, A3, T)> {
template <void (*fp)(A0, A1, A2, A3, T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value,
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename T, typename R, typename A0, typename A1, typename A2, typename A3>
struct ObjLast<R (*)(A0, A1, A2, A3, T)> {
template <R (*fp)(A0, A1, A2, A3, T)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
new (gen->GetAddressOfReturnLocation()) Proxy<R>((fp)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value,
Proxy<T>::cast(gen->GetObject())));
}
};

template <typename T>
struct Id {
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&(Wrapper<T>::f<fn_ptr>)); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&(ObjFirst<T>::f<fn_ptr>)); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&(ObjLast<T>::f<fn_ptr>)); }
};

template <typename T>
Id<T> id(T fn_ptr) { return Id<T>(); }

#define WRAP_FN(name) (::gw::id(name).f< name >())
#define WRAP_MFN(ClassType, name) (::gw::id(&ClassType::name).f< &ClassType::name >())
#define WRAP_OBJ_FIRST(name) (::gw::id(name).of< name >())
#define WRAP_OBJ_LAST(name) (::gw::id(name).ol< name >())

#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (*)Parameters>::f< name >))
#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::f< &ClassType::name >))
#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst<ReturnType (*)Parameters>::f< name >))
#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast<ReturnType (*)Parameters>::f< name >))

} // end namespace gw

#endif
[/code]
A python script to regenerate the file in case four arguments aren't enough for you:
[code]
max_args = 4 # the maximum number of parameters to be processed

print """#ifndef AS_GEN_WRAPPER_H
#define AS_GEN_WRAPPER_H

#include "angelscript.h"
#include <new>

namespace gw {

template <typename T> class Proxy {
public:
T value;
Proxy(T value) : value(value) {}
static T cast(void * ptr) {
return reinterpret_cast<Proxy<T> *>(&ptr)->value;
}
private:
Proxy(const Proxy &);
Proxy & operator=(const Proxy &);
};

template <typename T> struct Wrapper {};
template <typename T> struct ObjFirst {};
template <typename T> struct ObjLast {};
"""

typename_list = "typename A0"
type_list = "A0"
arg_list = "\n static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value"
new_exp = "new (gen->GetAddressOfReturnLocation()) Proxy<R>"
obj_exp = "static_cast<T *>(gen->GetObject())->*"
obj_arg_exp = "\n Proxy<T>::cast(gen->GetObject())"

template = """template <{0}{1}>
struct {9}<{2} ({3}*)({7}){4}> {{
template <{2} ({3}*fp)({7}){4}>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {{
{5}(({6}fp)({8}));
}}
}};
"""

print template.format("", "", "void", "", "", "", "", "void", "", "Wrapper")
print template.format("typename R", "", "R", "", "", new_exp, "", "void", "", "Wrapper")
print template.format("typename T", "", "void", "T::", "", "", obj_exp, "void", "", "Wrapper")
print template.format("typename T, typename R", "", "R", "T::", "", new_exp, obj_exp, "void", "", "Wrapper")
print template.format("typename T", "", "void", "T::", " const", "", obj_exp, "void", "", "Wrapper")
print template.format("typename T, typename R", "", "R", "T::", " const", new_exp, obj_exp, "void", "", "Wrapper")

print template.format("typename T", "", "void", "", "", "", "", "T", obj_arg_exp, "ObjFirst")
print template.format("typename T, typename R", "", "R", "", "", new_exp, "", "T", obj_arg_exp, "ObjFirst")
print template.format("typename T", "", "void", "", "", "", "", "T", obj_arg_exp, "ObjLast")
print template.format("typename T, typename R", "", "R", "", "", new_exp, "", "T", obj_arg_exp, "ObjLast")

for i in range(0, max_args):
print template.format("", typename_list, "void", "", "", "", "", type_list, arg_list, "Wrapper")
print template.format("typename R, ", typename_list, "R", "", "", new_exp, "", type_list, arg_list, "Wrapper")
print template.format("typename T, ", typename_list, "void", "T::", "", "", obj_exp, type_list, arg_list, "Wrapper")
print template.format("typename T, typename R, ", typename_list, "R", "T::", "", new_exp, obj_exp, type_list, arg_list, "Wrapper")
print template.format("typename T, ", typename_list, "void", "T::", " const", "", obj_exp, type_list, arg_list, "Wrapper")
print template.format("typename T, typename R, ", typename_list, "R", "T::", " const", new_exp, obj_exp, type_list, arg_list, "Wrapper")

print template.format("typename T, ", typename_list, "void", "", "", "", "", "T, " + type_list, obj_arg_exp + "," + arg_list, "ObjFirst")
print template.format("typename T, typename R, ", typename_list, "R", "", "", new_exp, "", "T, " + type_list, obj_arg_exp + "," + arg_list, "ObjFirst")
print template.format("typename T, ", typename_list, "void", "", "", "", "", type_list + ", T", arg_list + "," + obj_arg_exp, "ObjLast")
print template.format("typename T, typename R, ", typename_list, "R", "", "", new_exp, "", type_list + ", T", arg_list + "," + obj_arg_exp, "ObjLast")

typename_list += ", typename A{0}".format(i + 1)
type_list += ", A{0}".format(i + 1)
arg_list += ",\n static_cast<Proxy <A{0}> *>(gen->GetAddressOfArg({0}))->value".format(i + 1)

print """template <typename T>
struct Id {
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&(Wrapper<T>::f<fn_ptr>)); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&(ObjFirst<T>::f<fn_ptr>)); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&(ObjLast<T>::f<fn_ptr>)); }
};

template <typename T>
Id<T> id(T fn_ptr) { return Id<T>(); }

#define WRAP_FN(name) (::gw::id(name).f< name >())
#define WRAP_MFN(ClassType, name) (::gw::id(&ClassType::name).f< &ClassType::name >())
#define WRAP_OBJ_FIRST(name) (::gw::id(name).of< name >())
#define WRAP_OBJ_LAST(name) (::gw::id(name).ol< name >())

#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (*)Parameters>::f< name >))
#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::f< &ClassType::name >))
#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst<ReturnType (*)Parameters>::f< name >))
#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast<ReturnType (*)Parameters>::f< name >))

} // end namespace gw

#endif"""
[/code]
A smart pointer header also good for up to four arguments:
[code]
#ifndef AS_SMART_POINTER_WRAPPER
#define AS_SMART_POINTER_WRAPPER

#include <new>
#include "angelscript.h"
#include <memory>

namespace spw {

template <typename T> struct Default {
static T f(void) { return T(); }
};
template <typename T> struct Default<T &> {
static T & f(void) { return *static_cast<T *>(0); }
};

template <typename T> class Proxy {
public:
T value;
Proxy(T value) : value(value) {}
private:
Proxy(const Proxy &);
Proxy & operator=(const Proxy &);
};

template <typename T, typename U, U T::*member_ptr>
U getter(const std::shared_ptr<T> & ptr) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
return Default<U>::f();
}
return (ptr.get())->*member_ptr;
}

template <typename T, typename U, U T::*member_ptr>
const U & ref_getter(const std::shared_ptr<T> & ptr) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
return Default<U &>::f();
}
return (ptr.get())->*member_ptr;
}

template <typename T, typename U, U T::*member_ptr>
void getter_gen(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<U>((ptr.get())->*member_ptr);
}
}

template <typename T, typename U, U T::*member_ptr>
void ref_getter_gen(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<U &>((ptr.get())->*member_ptr);
}
}

template <typename T, typename U, U T::*member_ptr>
void setter(const std::shared_ptr<T> & ptr, U value) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
} else {
(ptr.get())->*member_ptr = value;
}
}

template <typename T, typename U, U T::*member_ptr>
void ref_setter(const std::shared_ptr<T> & ptr, const U & value) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
} else {
(ptr.get())->*member_ptr = value;
}
}

template <typename T, typename U, U T::*member_ptr>
void setter_gen(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
} else {
(ptr.get())->*member_ptr = static_cast<Proxy<U> *>(gen->GetAddressOfArg(0))->value;
}
}

template <typename T, typename U, U T::*member_ptr>
void ref_setter_gen(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
} else {
(ptr.get())->*member_ptr = static_cast<Proxy<U &> *>(gen->GetAddressOfArg(0))->value;
}
}

template <typename T> struct Caller {};
template <typename T> struct GenCaller {};

template <typename T, typename R>
struct Caller<R (T::*)(void)> {
template <R (T::*fn)(void)>
static R f(std::shared_ptr<T> & ptr) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)();
}
}
};

template <typename T, typename R>
struct Caller<R (T::*)(void) const> {
template <R (T::*fn)(void) const>
static R f(std::shared_ptr<T> & ptr) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)();
}
}
};

template <typename T>
struct GenCaller<void (T::*)(void)> {
template <void (T::*fn)(void)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)();
}
}
};

template <typename T, typename R>
struct GenCaller<R (T::*)(void)> {
template <R (T::*fn)(void)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)());
}
}
};

template <typename T>
struct GenCaller<void (T::*)(void) const> {
template <void (T::*fn)(void) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)();
}
}
};

template <typename T, typename R>
struct GenCaller<R (T::*)(void) const> {
template <R (T::*fn)(void) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)());
}
}
};

template <typename T, typename R, typename A0>
struct Caller<R (T::*)(A0)> {
template <R (T::*fn)(A0)>
static R f(std::shared_ptr<T> & ptr, A0 a0) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)(a0);
}
}
};

template <typename T, typename R, typename A0>
struct Caller<R (T::*)(A0) const> {
template <R (T::*fn)(A0) const>
static R f(std::shared_ptr<T> & ptr, A0 a0) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)(a0);
}
}
};

template <typename T, typename A0>
struct GenCaller<void (T::*)(A0)> {
template <void (T::*fn)(A0)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value);
}
}
};

template <typename T, typename R, typename A0>
struct GenCaller<R (T::*)(A0)> {
template <R (T::*fn)(A0)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
}
};

template <typename T, typename A0>
struct GenCaller<void (T::*)(A0) const> {
template <void (T::*fn)(A0) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value);
}
}
};

template <typename T, typename R, typename A0>
struct GenCaller<R (T::*)(A0) const> {
template <R (T::*fn)(A0) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value));
}
}
};

template <typename T, typename R, typename A0, typename A1>
struct Caller<R (T::*)(A0, A1)> {
template <R (T::*fn)(A0, A1)>
static R f(std::shared_ptr<T> & ptr, A0 a0, A1 a1) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)(a0, a1);
}
}
};

template <typename T, typename R, typename A0, typename A1>
struct Caller<R (T::*)(A0, A1) const> {
template <R (T::*fn)(A0, A1) const>
static R f(std::shared_ptr<T> & ptr, A0 a0, A1 a1) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)(a0, a1);
}
}
};

template <typename T, typename A0, typename A1>
struct GenCaller<void (T::*)(A0, A1)> {
template <void (T::*fn)(A0, A1)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value);
}
}
};

template <typename T, typename R, typename A0, typename A1>
struct GenCaller<R (T::*)(A0, A1)> {
template <R (T::*fn)(A0, A1)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
}
};

template <typename T, typename A0, typename A1>
struct GenCaller<void (T::*)(A0, A1) const> {
template <void (T::*fn)(A0, A1) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value);
}
}
};

template <typename T, typename R, typename A0, typename A1>
struct GenCaller<R (T::*)(A0, A1) const> {
template <R (T::*fn)(A0, A1) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value));
}
}
};

template <typename T, typename R, typename A0, typename A1, typename A2>
struct Caller<R (T::*)(A0, A1, A2)> {
template <R (T::*fn)(A0, A1, A2)>
static R f(std::shared_ptr<T> & ptr, A0 a0, A1 a1, A2 a2) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)(a0, a1, a2);
}
}
};

template <typename T, typename R, typename A0, typename A1, typename A2>
struct Caller<R (T::*)(A0, A1, A2) const> {
template <R (T::*fn)(A0, A1, A2) const>
static R f(std::shared_ptr<T> & ptr, A0 a0, A1 a1, A2 a2) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)(a0, a1, a2);
}
}
};

template <typename T, typename A0, typename A1, typename A2>
struct GenCaller<void (T::*)(A0, A1, A2)> {
template <void (T::*fn)(A0, A1, A2)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value);
}
}
};

template <typename T, typename R, typename A0, typename A1, typename A2>
struct GenCaller<R (T::*)(A0, A1, A2)> {
template <R (T::*fn)(A0, A1, A2)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
}
};

template <typename T, typename A0, typename A1, typename A2>
struct GenCaller<void (T::*)(A0, A1, A2) const> {
template <void (T::*fn)(A0, A1, A2) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value);
}
}
};

template <typename T, typename R, typename A0, typename A1, typename A2>
struct GenCaller<R (T::*)(A0, A1, A2) const> {
template <R (T::*fn)(A0, A1, A2) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value));
}
}
};

template <typename T, typename R, typename A0, typename A1, typename A2, typename A3>
struct Caller<R (T::*)(A0, A1, A2, A3)> {
template <R (T::*fn)(A0, A1, A2, A3)>
static R f(std::shared_ptr<T> & ptr, A0 a0, A1 a1, A2 a2, A3 a3) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)(a0, a1, a2, a3);
}
}
};

template <typename T, typename R, typename A0, typename A1, typename A2, typename A3>
struct Caller<R (T::*)(A0, A1, A2, A3) const> {
template <R (T::*fn)(A0, A1, A2, A3) const>
static R f(std::shared_ptr<T> & ptr, A0 a0, A1 a1, A2 a2, A3 a3) {
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
} else {
return ((ptr.get())->*fn)(a0, a1, a2, a3);
}
}
};

template <typename T, typename A0, typename A1, typename A2, typename A3>
struct GenCaller<void (T::*)(A0, A1, A2, A3)> {
template <void (T::*fn)(A0, A1, A2, A3)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value);
}
}
};

template <typename T, typename R, typename A0, typename A1, typename A2, typename A3>
struct GenCaller<R (T::*)(A0, A1, A2, A3)> {
template <R (T::*fn)(A0, A1, A2, A3)>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
}
};

template <typename T, typename A0, typename A1, typename A2, typename A3>
struct GenCaller<void (T::*)(A0, A1, A2, A3) const> {
template <void (T::*fn)(A0, A1, A2, A3) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value);
}
}
};

template <typename T, typename R, typename A0, typename A1, typename A2, typename A3>
struct GenCaller<R (T::*)(A0, A1, A2, A3) const> {
template <R (T::*fn)(A0, A1, A2, A3) const>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {
std::shared_ptr<T> & ptr = *static_cast<std::shared_ptr<T> *>(gen->GetObject());
if (!ptr) {
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
} else {
new (gen->GetAddressOfReturnLocation()) Proxy<R>(((ptr.get())->*fn)(
static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value,
static_cast<Proxy <A1> *>(gen->GetAddressOfArg(1))->value,
static_cast<Proxy <A2> *>(gen->GetAddressOfArg(2))->value,
static_cast<Proxy <A3> *>(gen->GetAddressOfArg(3))->value));
}
}
};

template <typename T, typename U>
struct GetSet {
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr g(void) { return asFUNCTION(( &getter <T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr rg(void) { return asFUNCTION((&ref_getter <T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr gg(void) { return asFUNCTION(( &getter_gen<T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr rgg(void) { return asFUNCTION((&ref_getter_gen<T, U, member_ptr>)); }

template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr s(void) { return asFUNCTION((&setter <T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr rs(void) { return asFUNCTION((&ref_setter <T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr sg(void) { return asFUNCTION(( &setter_gen<T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr rsg(void) { return asFUNCTION((&ref_setter_gen<T, U, member_ptr>)); }
};

template <typename T, typename U>
GetSet<T, U> gs_id(U T::*) { return GetSet<T, U>(); }

#define GETTER(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).g<&ClassName::member_name>())
#define REF_GETTER(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).rg<&ClassName::member_name>())
#define GETTER_GEN(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).gg<&ClassName::member_name>())
#define REF_GETTER_GEN(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).rgg<&ClassName::member_name>())

#define SETTER(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).s<&ClassName::member_name>())
#define REF_SETTER(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).rs<&ClassName::member_name>())
#define SETTER_GEN(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).sg<&ClassName::member_name>())
#define REF_SETTER_GEN(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).rsg<&ClassName::member_name>())

template <typename T>
struct CCaller {
template <T ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr c(void) { return asFUNCTION(&(Caller<T>::f<ptr>)); }
template <T ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr g(void) { return asFUNCTION(&(GenCaller<T>::f<ptr>)); }
};

template <typename T>
CCaller<T> caller_id(T) { return CCaller<T>(); }

#define CALLER(ClassName, member_name) (::spw::caller_id(&ClassName::member_name).c< &ClassName::member_name >())
#define GEN_CALLER(ClassName, member_name) (::spw::caller_id(&ClassName::member_name).g< &ClassName::member_name >())
#define CALLER_PR(ClassName, member_name, Args, Return) asFUNCTION((::spw::Caller<Return (ClassName::*)Args>::f< &ClassName::member_name >))
#define GEN_CALLER_PR(ClassName, member_name, Args, Return) asFUNCTION((::spw::GenCaller<Return (ClassName::*)Args>::f< &ClassName::member_name >))

} // end namespace spw

#endif
[/code]
Another python script, again, if four arguments aren't enough:
[code]
pointer_header = "<memory>" # which C++ header should be included
pointer_type = "std::shared_ptr<T>" # the name of the smart pointer parameterized on T
get_pointer = "(ptr.get())" # an expression that converts a smart pointer named ptr to T *
max_args = 4 # the maximum number of parameters to be processed

print """#ifndef AS_SMART_POINTER_WRAPPER
#define AS_SMART_POINTER_WRAPPER

#include <new>
#include "angelscript.h"
#include {0}
""".format(pointer_header)

print """namespace spw {

template <typename T> struct Default {
static T f(void) { return T(); }
};
template <typename T> struct Default<T &> {
static T & f(void) { return *static_cast<T *>(0); }
};

template <typename T> class Proxy {
public:
T value;
Proxy(T value) : value(value) {}
private:
Proxy(const Proxy &);
Proxy & operator=(const Proxy &);
};
"""

print """template <typename T, typename U, U T::*member_ptr>
U getter(const {0} & ptr) {{
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
return Default<U>::f();
}}
return {1}->*member_ptr;
}}

template <typename T, typename U, U T::*member_ptr>
const U & ref_getter(const {0} & ptr) {{
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
return Default<U &>::f();
}}
return {1}->*member_ptr;
}}

template <typename T, typename U, U T::*member_ptr>
void getter_gen(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {{
{0} & ptr = *static_cast<{0} *>(gen->GetObject());
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
}} else {{
new (gen->GetAddressOfReturnLocation()) Proxy<U>({1}->*member_ptr);
}}
}}

template <typename T, typename U, U T::*member_ptr>
void ref_getter_gen(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {{
{0} & ptr = *static_cast<{0} *>(gen->GetObject());
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
}} else {{
new (gen->GetAddressOfReturnLocation()) Proxy<U &>({1}->*member_ptr);
}}
}}

template <typename T, typename U, U T::*member_ptr>
void setter(const {0} & ptr, U value) {{
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
}} else {{
{1}->*member_ptr = value;
}}
}}

template <typename T, typename U, U T::*member_ptr>
void ref_setter(const {0} & ptr, const U & value) {{
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
}} else {{
{1}->*member_ptr = value;
}}
}}

template <typename T, typename U, U T::*member_ptr>
void setter_gen(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {{
{0} & ptr = *static_cast<{0} *>(gen->GetObject());
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
}} else {{
{1}->*member_ptr = static_cast<Proxy<U> *>(gen->GetAddressOfArg(0))->value;
}}
}}

template <typename T, typename U, U T::*member_ptr>
void ref_setter_gen(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {{
{0} & ptr = *static_cast<{0} *>(gen->GetObject());
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to access member of a null pointer");
}} else {{
{1}->*member_ptr = static_cast<Proxy<U &> *>(gen->GetAddressOfArg(0))->value;
}}
}}
""".format(pointer_type, get_pointer)

print """template <typename T> struct Caller {};
template <typename T> struct GenCaller {};
"""

typename_list = ", typename A0"
type_list = "A0"
parameter_list = ", A0 a0"
arg_list = "a0"
gen_arg_list = "\n static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value"

caller = """template <typename T, typename R{0}>
struct Caller<R (T::*)({1}){6}> {{
template <R (T::*fn)({1}){6}>
static R f({2} & ptr{3}) {{
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
return Default<R>::f();
}} else {{
return ({4}->*fn)({5});
}}
}}
}};
"""

gen_caller = """template <typename T{0}>
struct GenCaller<void (T::*)({1}){6}> {{
template <void (T::*fn)({1}){6}>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {{
{2} & ptr = *static_cast<{2} *>(gen->GetObject());
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
}} else {{
({4}->*fn)({5});
}}
}}
}};

template <typename T, typename R{0}>
struct GenCaller<R (T::*)({1}){6}> {{
template <R (T::*fn)({1}){6}>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {{
{2} & ptr = *static_cast<{2} *>(gen->GetObject());
if (!ptr) {{
AS_NAMESPACE_QUALIFIER asIScriptContext * ctx = AS_NAMESPACE_QUALIFIER asGetActiveContext();
ctx->SetException("Attempting to call member function of a null pointer");
}} else {{
new (gen->GetAddressOfReturnLocation()) Proxy<R>(({4}->*fn)({5}));
}}
}}
}};
"""

print caller.format("", "void", pointer_type, "", get_pointer, "", "")
print caller.format("", "void", pointer_type, "", get_pointer, "", " const")
print gen_caller.format("", "void", pointer_type, "", get_pointer, "", "")
print gen_caller.format("", "void", pointer_type, "", get_pointer, "", " const")

print caller.format(typename_list, type_list, pointer_type, parameter_list, get_pointer, arg_list, "")
print caller.format(typename_list, type_list, pointer_type, parameter_list, get_pointer, arg_list, " const")
print gen_caller.format(typename_list, type_list, pointer_type, parameter_list, get_pointer, gen_arg_list, "")
print gen_caller.format(typename_list, type_list, pointer_type, parameter_list, get_pointer, gen_arg_list, " const")

for i in range(1, max_args):
typename_list += ", typename A{0}".format(i)
type_list += ", A{0}".format(i)
parameter_list += ", A{0} a{0}".format(i)
arg_list += ", a{0}".format(i)
gen_arg_list += ",\n static_cast<Proxy <A{0}> *>(gen->GetAddressOfArg({0}))->value".format(i)

print caller.format(typename_list, type_list, pointer_type, parameter_list, get_pointer, arg_list, "")
print caller.format(typename_list, type_list, pointer_type, parameter_list, get_pointer, arg_list, " const")
print gen_caller.format(typename_list, type_list, pointer_type, parameter_list, get_pointer, gen_arg_list, "")
print gen_caller.format(typename_list, type_list, pointer_type, parameter_list, get_pointer, gen_arg_list, " const")

print """template <typename T, typename U>
struct GetSet {
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr g(void) { return asFUNCTION(( &getter <T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr rg(void) { return asFUNCTION((&ref_getter <T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr gg(void) { return asFUNCTION(( &getter_gen<T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr rgg(void) { return asFUNCTION((&ref_getter_gen<T, U, member_ptr>)); }

template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr s(void) { return asFUNCTION((&setter <T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr rs(void) { return asFUNCTION((&ref_setter <T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr sg(void) { return asFUNCTION(( &setter_gen<T, U, member_ptr>)); }
template <U T::* member_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr rsg(void) { return asFUNCTION((&ref_setter_gen<T, U, member_ptr>)); }
};

template <typename T, typename U>
GetSet<T, U> gs_id(U T::*) { return GetSet<T, U>(); }

#define GETTER(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).g<&ClassName::member_name>())
#define REF_GETTER(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).rg<&ClassName::member_name>())
#define GETTER_GEN(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).gg<&ClassName::member_name>())
#define REF_GETTER_GEN(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).rgg<&ClassName::member_name>())

#define SETTER(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).s<&ClassName::member_name>())
#define REF_SETTER(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).rs<&ClassName::member_name>())
#define SETTER_GEN(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).sg<&ClassName::member_name>())
#define REF_SETTER_GEN(ClassName, member_name) (::spw::gs_id(&ClassName::member_name).rsg<&ClassName::member_name>())

template <typename T>
struct CCaller {
template <T ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr c(void) { return asFUNCTION(&(Caller<T>::f<ptr>)); }
template <T ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr g(void) { return asFUNCTION(&(GenCaller<T>::f<ptr>)); }
};

template <typename T>
CCaller<T> caller_id(T) { return CCaller<T>(); }

#define CALLER(ClassName, member_name) (::spw::caller_id(&ClassName::member_name).c< &ClassName::member_name >())
#define GEN_CALLER(ClassName, member_name) (::spw::caller_id(&ClassName::member_name).g< &ClassName::member_name >())
#define CALLER_PR(ClassName, member_name, Args, Return) asFUNCTION((::spw::Caller<Return (ClassName::*)Args>::f< &ClassName::member_name >))
#define GEN_CALLER_PR(ClassName, member_name, Args, Return) asFUNCTION((::spw::GenCaller<Return (ClassName::*)Args>::f< &ClassName::member_name >))

} // end namespace spw

#endif"""
[/code]
Python code was developed on CPython 2.6.
0

Share this post


Link to post
Share on other sites
This looks really great. I'm impressed as always with template magic you manage to conjure. :)

I'll take a closer look at this for version 2.22.2 and include it as an add-on.

It's definitely a major benefit not to have to declare and register the wrappers at two different locations.

I'll think about a way to avoid having the difference in the variable (?&) parameter types. Perhaps the reference and type can be passed in a simple pod-structure to C++ instead so it can be considered a single argument.

0

Share this post


Link to post
Share on other sites
Well, it'd be easiest if generic functions could receive the type ids as additional parameters like native functions. Then the code would work as is. Maybe an engine property or an additional flag on top of asCALL_GENERIC? Though, I'm not sure how much practical difference supporting variable parameters would have. The rest of the wrappers take C++ code that would exist regularly, but the variable parameter functions have to be written specifically with AngelScript in mind, so if someone needed generic calling convention he would probably just write it that way in the first place.
0

Share this post


Link to post
Share on other sites
Took the time today to do proof of concept implementation of the variable parameter type with the struct argument option. Seems to work, or at least I was able to use it to get the scripthandle add-on to pass test_feature with AS_MAX_PORTABILITY defined on revision 1109.

scripthandle.cpp modification:
[code]
void construct(CScriptHandle * self, ::gw::VariableParameter v) {
Construct(self, v.object, v.type_id);
}

void ref_cast(CScriptHandle * self, ::gw::VariableParameter v) {
self->opCast(reinterpret_cast<void **>(v.object), v.type_id);
}

CScriptHandle * op_assign(CScriptHandle * self, ::gw::VariableParameter v) {
return &(self->opAssign(v.object, v.type_id));
}

bool op_equals(CScriptHandle * self, ::gw::VariableParameter v) {
return self->opEquals(v.object, v.type_id);
}

void RegisterScriptHandle_Generic(asIScriptEngine *engine)
{
int r;

r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", WRAP_OBJ_FIRST_PR(Construct, (CScriptHandle *), void), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", WRAP_OBJ_FIRST_PR(Construct, (CScriptHandle *, const CScriptHandle &), void), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", WRAP_OBJ_FIRST_PR(Destruct, (CScriptHandle *), void), asCALL_GENERIC); assert( r >= 0 );

r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", WRAP_OBJ_FIRST(construct), asCALL_GENERIC); assert( r >= 0 );

r = engine->RegisterObjectMethod("ref", "ref &opAssign(const ref &in)", WRAP_MFN(CScriptHandle, operator=), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", WRAP_MFN_PR(CScriptHandle, opEquals, (const CScriptHandle &) const, bool), asCALL_GENERIC); assert( r >= 0 );

r = engine->RegisterObjectBehaviour("ref", asBEHAVE_REF_CAST, "void f(?&out)", WRAP_OBJ_FIRST(ref_cast), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("ref", "ref &opAssign(const ?&in)", WRAP_OBJ_FIRST(op_assign), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", WRAP_OBJ_FIRST(op_equals), asCALL_GENERIC); assert( r >= 0 );
}

void RegisterScriptHandle(asIScriptEngine *engine)
{
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
RegisterScriptHandle_Generic(engine);
else
RegisterScriptHandle_Native(engine);
}
[/code]

New Python code:
[code]
max_args = 4 # the maximum number of parameters to be processed

print """#ifndef AS_GEN_WRAPPER_H
#define AS_GEN_WRAPPER_H

#include "angelscript.h"
#include <new>

namespace gw {

template <typename T> class Proxy {
public:
T value;
Proxy(T value) : value(value) {}
static T cast(void * ptr) {
return reinterpret_cast<Proxy<T> *>(&ptr)->value;
}
private:
Proxy(const Proxy &);
Proxy & operator=(const Proxy &);
};

struct VariableParameter {
void * object;
int type_id;

VariableParameter(void * obj, int type) : object(obj), type_id(type) {}
};

template <typename T> struct Arg {
static T arg(asIScriptGeneric * gen, int i) {
return static_cast<Proxy <T> *>(gen->GetAddressOfArg(i))->value;
}
};

template <> struct Arg<VariableParameter> {
static VariableParameter arg(asIScriptGeneric * gen, int i) {
return VariableParameter(gen->GetArgAddress(i), gen->GetArgTypeId(i));
}
};

template <typename T> struct Wrapper {};
template <typename T> struct ObjFirst {};
template <typename T> struct ObjLast {};
"""

typename_list = "typename A0"
type_list = "A0"
arg_list = "\n Arg<A0>::arg(gen, 0)"
new_exp = "new (gen->GetAddressOfReturnLocation()) Proxy<R>"
obj_exp = "static_cast<T *>(gen->GetObject())->*"
obj_arg_exp = "\n Proxy<T>::cast(gen->GetObject())"

template = """template <{0}{1}>
struct {9}<{2} ({3}*)({7}){4}> {{
template <{2} ({3}*fp)({7}){4}>
static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {{
{5}(({6}fp)({8}));
}}
}};
"""

print template.format("", "", "void", "", "", "", "", "void", "", "Wrapper")
print template.format("typename R", "", "R", "", "", new_exp, "", "void", "", "Wrapper")
print template.format("typename T", "", "void", "T::", "", "", obj_exp, "void", "", "Wrapper")
print template.format("typename T, typename R", "", "R", "T::", "", new_exp, obj_exp, "void", "", "Wrapper")
print template.format("typename T", "", "void", "T::", " const", "", obj_exp, "void", "", "Wrapper")
print template.format("typename T, typename R", "", "R", "T::", " const", new_exp, obj_exp, "void", "", "Wrapper")

print template.format("typename T", "", "void", "", "", "", "", "T", obj_arg_exp, "ObjFirst")
print template.format("typename T, typename R", "", "R", "", "", new_exp, "", "T", obj_arg_exp, "ObjFirst")
print template.format("typename T", "", "void", "", "", "", "", "T", obj_arg_exp, "ObjLast")
print template.format("typename T, typename R", "", "R", "", "", new_exp, "", "T", obj_arg_exp, "ObjLast")

for i in range(0, max_args):
print template.format("", typename_list, "void", "", "", "", "", type_list, arg_list, "Wrapper")
print template.format("typename R, ", typename_list, "R", "", "", new_exp, "", type_list, arg_list, "Wrapper")
print template.format("typename T, ", typename_list, "void", "T::", "", "", obj_exp, type_list, arg_list, "Wrapper")
print template.format("typename T, typename R, ", typename_list, "R", "T::", "", new_exp, obj_exp, type_list, arg_list, "Wrapper")
print template.format("typename T, ", typename_list, "void", "T::", " const", "", obj_exp, type_list, arg_list, "Wrapper")
print template.format("typename T, typename R, ", typename_list, "R", "T::", " const", new_exp, obj_exp, type_list, arg_list, "Wrapper")

print template.format("typename T, ", typename_list, "void", "", "", "", "", "T, " + type_list, obj_arg_exp + "," + arg_list, "ObjFirst")
print template.format("typename T, typename R, ", typename_list, "R", "", "", new_exp, "", "T, " + type_list, obj_arg_exp + "," + arg_list, "ObjFirst")
print template.format("typename T, ", typename_list, "void", "", "", "", "", type_list + ", T", arg_list + "," + obj_arg_exp, "ObjLast")
print template.format("typename T, typename R, ", typename_list, "R", "", "", new_exp, "", type_list + ", T", arg_list + "," + obj_arg_exp, "ObjLast")

typename_list += ", typename A{0}".format(i + 1)
type_list += ", A{0}".format(i + 1)
arg_list += ",\n Arg<A{0}>::arg(gen, {0})".format(i + 1)

print """template <typename T>
struct Id {
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&(Wrapper<T>::f<fn_ptr>)); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&(ObjFirst<T>::f<fn_ptr>)); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&(ObjLast<T>::f<fn_ptr>)); }
};

template <typename T>
Id<T> id(T fn_ptr) { return Id<T>(); }

#define WRAP_FN(name) (::gw::id(name).f< name >())
#define WRAP_MFN(ClassType, name) (::gw::id(&ClassType::name).f< &ClassType::name >())
#define WRAP_OBJ_FIRST(name) (::gw::id(name).of< name >())
#define WRAP_OBJ_LAST(name) (::gw::id(name).ol< name >())

#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (*)Parameters>::f< name >))
#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::f< &ClassType::name >))
#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst<ReturnType (*)Parameters>::f< name >))
#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast<ReturnType (*)Parameters>::f< name >))

} // end namespace gw

#endif"""
[/code]
0

Share this post


Link to post
Share on other sites
Cool. Thanks for adding support for this too.

Though I'm not quite sure this will be fully portable. Depending on the OS and compiler the VariableParameter structure will not always be passed the same way the two parameters is today. This means the native function that receives a VariableParameter cannot be used without the wrapper, unless I change the library to always pass the ? args as a VariableParameter structure.
0

Share this post


Link to post
Share on other sites
Yeah, the idea was to see if you decide to change the mechanism AngelScript uses from the void * and type id arguments to a combined structure like you said at the end of your first response, if the code could be modified to account for that - which it seems it can. Even without that, it does simplify writing the wrappers for the variable parameter functions, but that's more of a happy accident than what I was looking at.
0

Share this post


Link to post
Share on other sites
I finally got the time to give these a try in order to include them in the SDK, and I quickly discovered that the code relies quite heavily on C++11 features. While this is not a bad thing, and I personally like keeping up to date with new language feature it does make it difficult to include it as a standard add-on in AngelScript at this moment as C++11 still isn't all that widespread.

Instead I put together the files in a small package and uploaded it to my site:

[url="http://www.angelcode.com/angelscript/resources.html"]http://www.angelcode.com/angelscript/resources.html[/url]


Regards,
Andreas
0

Share this post


Link to post
Share on other sites
It shouldn't require C++11, I got it to work with MSVC 2008. The smart pointer wrappers use std::shared_ptr as an example, but you can switch out for boost::shared_ptr, or whatever other smart pointer you like.
0

Share this post


Link to post
Share on other sites
Have you thought about using BOOST_PP for automatic expansion of the wrapper, it would avoid the tedious step of having to generate the wrapper class for N arguments, as you could just use BOOST_PP to do it for you?
0

Share this post


Link to post
Share on other sites
Yes, that's how I wrote some previous wrappers, which you can find via the external resources on the AngelScript wiki. However, Andreas doesn't really like external dependencies like boost for add-ons, hence the code generator.
0

Share this post


Link to post
Share on other sites
You're right. It was only the smart pointer wrapper that failed to compile on MSVC2008. I'll use the auto wrapper for the generic calling functions after all :)

But I'll keep the smart pointer wrapper as the extra download for now, to avoid adding dependencies (even though it is just for an add-on).


Thanks for correcting me. I was too quick to discard it without really looking into what was failing.

Regards,
Andreas
0

Share this post


Link to post
Share on other sites
I added the new code in revision 1187.

It works well on MSVC++ 2008. Unfortunately I get an error on gnuc as can be seen in [url="http://angelscript.jeremyh.net/builders/Full-Linux/builds/375/steps/compile_1/logs/stdio"]the buildbot output[/url].

The error is related to the following

[code]

template <typename T>
struct Id {
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&(Wrapper<T>::f<fn_ptr>)); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&(ObjFirst<T>::f<fn_ptr>)); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&(ObjLast<T>::f<fn_ptr>)); }
};
[/code]

It seems the gnuc compiler doesn't like the argument to the asFUNCTION macro. Any idea what is wrong? Or how I can get it to work on gnuc too?
0

Share this post


Link to post
Share on other sites
g++ might be stricter about the extra parenthesis. Try
[code]
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&Wrapper<T>::f<fn_ptr>); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&ObjFirst<T>::f<fn_ptr>); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&ObjLast<T>::f<fn_ptr>); }
[/code]
0

Share this post


Link to post
Share on other sites
Still doesn't work. I get the same error message.


The PR versions work without a hitch though, so it is specific for the non-PR versions.
0

Share this post


Link to post
Share on other sites
This is the qualified names aren't treated as templates unless you use the template keyword rule that I always forget about when porting code from MSVC to stricter compilers. Try:
[code]
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&Wrapper<T>::template f<fn_ptr>); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&ObjFirst<T>::template f<fn_ptr>); }
template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&ObjLast<T>::template f<fn_ptr>); }
[/code]
Tested with g++ 4.5.3 and clang 3.1 this time, so hopefully it's good.
0

Share this post


Link to post
Share on other sites
Running against clang will usually print out readable AND understandable errors. GCC errors never make sense :)
0

Share this post


Link to post
Share on other sites
Actually, clang wasn't too helpful this time. It just gave an expected expression error, which is more or less what gcc said as well. It makes sense if you remember that the trailing > was being parsed as a greater than rather than template delimiter, otherwise not so much.
0

Share this post


Link to post
Share on other sites
Andreas, the [url="http://www.angelcode.com/angelscript/resources.html"]available D/L[/url] currently has older non-G++/etc code still in it. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

Also, the example main.cpp still uses the older CALLER define, while the headers use WRAP_*. Which leads to a question for anyone to answer: how are those examples supposed to be written? The registration I'm using in my code keeps returning asWRONG_CALLING_CONV, aka the value -24, with no report from the callback.
[CODE]

//[[From #include'd header]]
class Entity;
typedef std::shared_ptr<Entity> EntitySPTR;

//[[From class Entity's declaration]]

public:

void ChangeScale(float);
//...

//[[From registration code]]
int ret = 0;

// Register Object
ret = engine->RegisterObjectType("Entity", sizeof(EntitySPTR), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert(ret >= 0);

// Register behaviors and operations
ret = engine->RegisterObjectBehaviour("Entity", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(construct<EntitySPTR>), asCALL_CDECL_OBJFIRST); assert(ret >= 0);
ret = engine->RegisterObjectBehaviour("Entity", asBEHAVE_CONSTRUCT, "void f(const Entity & in)", asFUNCTION(copy_construct<EntitySPTR>), asCALL_CDECL_OBJFIRST); assert(ret >= 0);
ret = engine->RegisterObjectBehaviour("Entity", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(destroy<EntitySPTR>), asCALL_CDECL_OBJFIRST); assert(ret >= 0);
ret = engine->RegisterObjectMethod("Entity", "Entity &opAssign(const Entity &in)", asFUNCTION(assign<EntitySPTR>), asCALL_CDECL_OBJFIRST); assert(ret >= 0);

// Register methods
ret = engine->RegisterObjectMethod("Entity", "void ChangeScale(float)", WRAP_MFN(Entity, ChangeScale), asCALL_CDECL_OBJFIRST); assert(ret >= 0);
[/CODE]

RegisterObjectMethod is returning -24, causing the assert to fail. I know that the manual recommends against looking at the return value for any debug help, but since the callback wan't reporting anything...

Thanks for the info, and to all of you for the work required to make this in the first place!
0

Share this post


Link to post
Share on other sites
The functions returned by WRAP_MFN() are generic calling conventions so should be registered with asCALL_GENERIC. Since it looks like you're using native calling conventions, then you don't need to use WRAP_MFN(), etc. Just use asMETHOD and asCALL_THISCALL. You would use these if you want to create generic calling convention wrappers for native functions. For example, if your platform doesn't support native calls.
1

Share this post


Link to post
Share on other sites
Ah, I was so distracted by the example main that I forgot to try the simple route - you are correct that I am using the native calling convention.
[left]asMETHOD and asCALL_THISCALL worked like a charm, thanks![/left]

Now that that's in place and I've cleaned out all the @'s in my code, (I'm converting my system over to SPTRs from normal pointers,) now all I have left is to figure out how to work around the fact that while I can assign null to these, I can't compare to null: I can't find any info on how to overload the "is null" operator! :/ The reason is that my script has a function with an optional parameter that is defaulted to null:
[CODE]
// Yes, this isn't a C&P from my code; the code's too verbose for this example.

void myFunc(const string &in name, Entity entity = null) {
//...
if (!(parent_entity is null)) {
//...
}
//...
}
[/CODE]
(The above code fails AS compilation with "No conversion from '<null handle>' to 'Entity' available.")

I'm thinking I might just overload the function with one that doesn't have the second option and just have one call the other. (Or, as these are actually constructors in a script class in my actual code, have both of them call a private method that does the work...)
0

Share this post


Link to post
Share on other sites
Bypassing the null problem worked. But now my entire stack of cards seems to have fallen down: the script sptr heads off to uninit'd memory. I'm probably missing something simple again, but after several hours of work, I've made little progress.

File: sptrtypes.h
[CODE]

// Library Includes
#include <angelscript/sptrwrapper/as_smart_ptr_wrapper.h>

// Local Includes
#include "../sharedbase/Entity.h"

// Forward Declarations

// Typedefs

// Functions

// Helper functions

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
template <typename T>
void construct(void* address) {
new (address) T();
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
template <typename T>
void destroy(T* object) {
object->~T();
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
template <typename T>
void copy_construct(void* address, T* other) {
new (address) T(*other);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
template <typename T>
void assign(T * lhs, T* rhs) {
*lhs = *rhs;
}


// Registration functions

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void RegisterEntity(asIScriptEngine* const engine) {
int ret = 0;

// Register Object
ret = engine->RegisterObjectType("Entity", sizeof(EntitySPTR), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert(ret >= 0);

// Register behaviors and operations
ret = engine->RegisterObjectBehaviour("Entity", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Entity::FactoryAtAddress), asCALL_CDECL_OBJFIRST); assert(ret >= 0);
// ret = engine->RegisterObjectBehaviour("Entity", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(construct<EntitySPTR>), asCALL_CDECL_OBJFIRST); assert(ret >= 0);
ret = engine->RegisterObjectBehaviour("Entity", asBEHAVE_CONSTRUCT, "void f(const Entity &in)", asFUNCTION(copy_construct<EntitySPTR>), asCALL_CDECL_OBJFIRST); assert(ret >= 0);
ret = engine->RegisterObjectBehaviour("Entity", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(destroy<EntitySPTR>), asCALL_CDECL_OBJFIRST); assert(ret >= 0);
ret = engine->RegisterObjectMethod("Entity", "Entity &opAssign(const Entity &in)", asFUNCTION(assign<EntitySPTR>), asCALL_CDECL_OBJFIRST); assert(ret >= 0);

// Register properties
ret = engine->RegisterObjectProperty("Entity", "int id", offsetof(Entity, id)); assert(ret >= 0);
ret = engine->RegisterObjectProperty("Entity", "PropertyMap properties", offsetof(Entity, properties)); assert(ret >= 0);
ret = engine->RegisterObjectProperty("Entity", "float scale", offsetof(Entity, scale)); assert(ret >= 0);
ret = engine->RegisterObjectProperty("Entity", "Vector positionOffset", offsetof(Entity, location)); assert(ret >= 0);
ret = engine->RegisterObjectProperty("Entity", "Rotation rotationOffset", offsetof(Entity, rotation)); assert(ret >= 0);

// Register methods
ret = engine->RegisterObjectMethod("Entity", "void SetParent(Entity)", asMETHOD(Entity, SetParent), asCALL_THISCALL); assert(ret >= 0);
ret = engine->RegisterObjectMethod("Entity", "Entity GetParent()", asMETHOD(Entity, GetParent), asCALL_THISCALL); assert(ret >= 0);

ret = engine->RegisterObjectMethod("Entity", "void ChangeScale(float)", asMETHOD(Entity, ChangeScale), asCALL_THISCALL); assert(ret >= 0);
ret = engine->RegisterObjectMethod("Entity", "float GetWorldScale()", asMETHOD(Entity, GetWorldScale), asCALL_THISCALL); assert(ret >= 0);

ret = engine->RegisterObjectMethod("Entity", "Vector GetWorldPosition()", asMETHOD(Entity, GetWorldPosition), asCALL_THISCALL); assert(ret >= 0);
ret = engine->RegisterObjectMethod("Entity", "void SetWorldPosition(float, float, float)", asMETHODPR(Entity, SetWorldPosition, (float, float, float), void), asCALL_THISCALL); assert(ret >= 0);
ret = engine->RegisterObjectMethod("Entity", "void ChangePosition(Vector)", asMETHODPR(Entity, ChangePosition, (D3DXVECTOR3), void), asCALL_THISCALL); assert(ret >= 0);

ret = engine->RegisterObjectMethod("Entity", "Rotation GetWorldRotation()", asMETHOD(Entity, GetWorldRotation), asCALL_THISCALL); assert(ret >= 0);
ret = engine->RegisterObjectMethod("Entity", "void SetRotation(float, float, float)", asMETHODPR(Entity, SetRotation, (float, float, float), void), asCALL_THISCALL); assert(ret >= 0);
ret = engine->RegisterObjectMethod("Entity", "void ChangeRotation(float, float, float)", asMETHODPR(Entity, ChangeRotation, (float, float, float), void), asCALL_THISCALL); assert(ret >= 0);
}

[/CODE]

Note: Entity has a private ctor.

Entity::Factory
[CODE]

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/// Creates a new Entity at the specified address.
void Entity::FactoryAtAddress(void* address) {
new (address) EntitySPTR(new Entity());
}


[/CODE]


Everything compiles fine, but when my test script runs, it has some strange crashes involving access violations in seemingly unrelated code.

Test Script"
[CODE]

void main(void) {
Log(FLOW, "main: Loadup script started.");

string test;

{
//Entity myEntity;
Entity myEntity;

myEntity.id = -12; // Access violation below involving a std::string when this is used.
// myEntity.id = 12; // Execution proceeds fine with this one.
}

{
test = "Entity without parens"; // This string is the one that gets the violation.

Entity myEntity;

Log(INFO, test + ": id is '" + myEntity.id + "' giving result: " + (myEntity.id == -1)); // Entity's ctor initializes this property to -1, so if this is pointed at the correct section of memory, one of these tests should return true. However, all return false.
}

{
test = "Entity with parens";

Entity myEntity();

Log(INFO, test + ": id is '" + myEntity.id + "' giving result: " + (myEntity.id == -1));
}

{
test = "Entity with assignment of ctor";

Entity myEntity = Entity();

Log(INFO, test + ": id is '" + myEntity.id + "' giving result: " + (myEntity.id == -1));
}

}

[/CODE]

This looks like VERY strange behavior to me, resulting in me coming to the conclusion that something in the registration is still wrong. Especially as it seems that I'm not even using anything from the as_smart_ptr_wrapper header...
0

Share this post


Link to post
Share on other sites
You must use the wrappers from the as_smart_ptr_wrapper.h when registering the functions. Otherwise you're registering the actual class methods, but AngelScript doesn't have the actual object pointer, so when the methods are called you're likely to have memory invasions, crashes, and other nasty problems.

Thanks for alerting me on the package I uploaded. I'll update it with the fixes. I also noticed I put the wrong code in the as_smart_ptr_wrapper.h so that needs to be fixed too.
1

Share this post


Link to post
Share on other sites
I've propagated the changes to the python files, here's the patch: [attachment=7476:wrapper_gen.patch.txt]

Now that I've run those python files to regenerate the headers I'm going to re-attempt my code, I'll let you know the results.
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0