Original Post
I had a giant function in my project that did nothing but call asIScriptEngine::RegisterGlobalFunction over and over. This bugged me. My current solution is still less than perfect, but, IMHO, much better. It does not require some other cpp file to include every header that happens to contain a function I need bound to angelscript. It allows me to say in the cpp file the function is defined in 'Hey, bind this with AS!'. It works by inserting code to be executed before main() begins into the program using the constructor of a static object. This code builds a list of functions to be registered using the command pattern. Right now, it only supports global functions, but could be easily expanded. AutoBind.h AutoBind.cpp usage
#ifndef JM_SERVER_AUTOBIND_H
#define JM_SERVER_AUTOBIND_H
#include <angelscript.h>
#define REG_NUM __LINE__
//Normally, the preprocessor pastes tokens before expanding them. REG_CAT gets around
//that problem by delaying concatanation until after expansion. I don't know how it
//works; I took this trick from boost.
#define REG_CAT(a,b) REG_CAT_I(a,b)
#define REG_CAT_I(a,b) REG_CAT_II(a ## b)
#define REG_CAT_II(a) a
//Must be in a CPP file. Inserts a call to AutoBind::BindGlobalFunction at program
//startup. Hides identifiers in anonymous namespace - safe across compilation units.
#define REGISTER_GLOBAL_FUNCTION(AS_STR,FUNC) namespace { class REG_CAT(RGF,REG_NUM) { public: REG_CAT(RGF,REG_NUM)() { AutoBind::BindGlobalFunction(AS_STR,FUNC); } }; REG_CAT(RGF,REG_NUM) REG_CAT(RGF_instance_,REG_NUM) ; };
namespace AutoBind
{
void Bind(asIScriptEngine*);
class Binder
{
public:
virtual void bind(asIScriptEngine*) = 0;
};
void PushBinder(Binder*);
template <typename T>
class TBinder : public Binder
{
public:
std::string in_as;
T fptr;
TBinder(const std::string& str, T fp) : in_as(str), fptr(fp) {}
virtual void bind(asIScriptEngine* engine)
{
engine->RegisterGlobalFunction(in_as.c_str(),fptr,asCALL_CDECL);
}
};
//Use the function argument to determine the type of the function pointer and generate
//the proper TBinder object
template <typename T>
void BindGlobalFunction(const std::string& str, T fp)
{
PushBinder(new TBinder<T>(str,fp));
}
};
#endif
#include "AutoBind.h"
#include <list>
namespace {
typedef std::list<AutoBind::Binder*> BinderList;
BinderList& GetBinder() //Static creation method
{
static BinderList binders;
return binders;
}
};
void AutoBind::PushBinder(AutoBind::Binder* b)
{
GetBinder().push_back(b);
}
void AutoBind::Bind(asIScriptEngine* engine)
{
while (!GetBinder().empty())
{
GetBinder().front()->bind(engine);
delete GetBinder().front();
GetBinder().pop_front();
}
}
#include "AutoBind.h"
void Function() {}
REGISTER_GLOBAL_FUNCTION("void Function()",asFUNCTION(Function));
int main()
{
//initiate script engine...
AutoBind::Bind(pointer_to_script_engine);
}