Jump to content

  • Log In with Google      Sign In   
  • Create Account

- - - - -

More AngelScript binding wrappers


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
28 replies to this topic

#1 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 18 December 2011 - 06:59 PM

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:
  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);
  }
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:
#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;
}
A header for the generic wrappers good for up to four arguments:
#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
A python script to regenerate the file in case four arguments aren't enough for you:
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"""
A smart pointer header also good for up to four arguments:
#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
Another python script, again, if four arguments aren't enough:
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"""
Python code was developed on CPython 2.6.

Sponsor:

#2 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 20 December 2011 - 06:14 PM

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.


AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#3 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 20 December 2011 - 07:06 PM

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.

#4 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 22 December 2011 - 07:44 PM

Good point. Still I like consistency, so I'll keep this in mind for a 'possible' future change.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#5 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 14 January 2012 - 05:58 PM

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

New Python 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"""


#6 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 14 January 2012 - 06:26 PM

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.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#7 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 14 January 2012 - 06:33 PM

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.

#8 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 19 February 2012 - 01:32 PM

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:

http://www.angelcode.com/angelscript/resources.html


Regards,
Andreas
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#9 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 19 February 2012 - 01:44 PM

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.

#10 Washu   Senior Moderators   -  Reputation: 5199

Like
0Likes
Like

Posted 19 February 2012 - 01:48 PM

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?

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX


#11 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 19 February 2012 - 02:08 PM

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.

#12 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 19 February 2012 - 02:51 PM

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
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#13 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 19 February 2012 - 06:01 PM

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 the buildbot output.

The error is related to the following


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

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?
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#14 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 19 February 2012 - 06:13 PM

g++ might be stricter about the extra parenthesis. Try
  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>); }


#15 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 19 February 2012 - 06:36 PM

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.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#16 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 19 February 2012 - 06:50 PM

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:
  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>); }
Tested with g++ 4.5.3 and clang 3.1 this time, so hopefully it's good.

#17 Andreas Jonsson   Moderators   -  Reputation: 3366

Like
0Likes
Like

Posted 19 February 2012 - 07:12 PM

That worked. Thanks a lot. :)

My knowledge of template programming is far too basic to spot these type of errors.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#18 Washu   Senior Moderators   -  Reputation: 5199

Like
0Likes
Like

Posted 19 February 2012 - 07:13 PM

Running against clang will usually print out readable AND understandable errors. GCC errors never make sense :)

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX


#19 SiCrane   Moderators   -  Reputation: 9598

Like
0Likes
Like

Posted 19 February 2012 - 07:16 PM

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.

#20 kf6kjg   Members   -  Reputation: 100

Like
0Likes
Like

Posted 26 February 2012 - 04:13 PM

Andreas, the available D/L currently has older non-G++/etc code still in it. Posted Image

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.

//[[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);

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!




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS