Function pointer with unknown agrs??

Started by
5 comments, last by _Sigma 16 years, 12 months ago
I'm trying to create a wrapper class to automate some of the anglescript setup. I would like to be able to wrap this function:

	virtual int RegisterGlobalFunction(const char *declaration, const asUPtr &funcPointer, asDWORD callConv) = 0;
To use the RegisterGlobalFunction, you have to wrap the function address in a 'asFunction' macro like:


r = engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString), asCALL_CDECL); assert( r >= 0 );


So I would like to somehow get rid of this, and automatically do this. My first go was this:
void TScript::ExposeFn( const std::string *declaration, const asUPtr &funcPointer )

but then I think I need the macro wrapper again. So I would really like something like:
void TScript::ExposeFn( const std::string *declaration, fnPtr &funcPointer )

where funcPointer could have any type of arguments and the underlying code would wrap the passed function in asFUNCTION and then pass it off to the angelscript function. I'm just not sure a)if this can be done b)how to any pointers would be great! Cheers
Advertisement
I don't quite follow. Do you want to be able to call any function, given only a pointer to the function (void* or whatever), and a variable argument list (So essentially make the call yourself)? If so, you'll have to do some assembly to push the relevant parameters onto the stack.
One of the Game Programming Gems gooks has a bit about this in it somewhere (I'll look it out tonight if this is what you need)
Ummm I dont see the problem, cant you just use templates?

template<typename FuncType>void TScript::ExposeFn( const std::string *declaration, FuncType &funcPointer )


If you want more type safety then you can use boost.preprocessor to generate template overloads for each number of arguments garunteing that the passef in item is actually a function

template<typename R>void TScript::ExposeFn( const std::string *declaration, R (&funcPointer)() )template<typename R, typename T0>void TScript::ExposeFn( const std::string *declaration, R (&funcPointer)(T0) )template<typename R, typename T0, typename T1>void TScript::ExposeFn( const std::string *declaration, R (&funcPointer)(T0, T1) )// Or with BOOST_PP#define GEN_OVERLOAD(z, n, data)                                  \ template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(n, typename T)> \     void TScript::ExposeFn( const std::string *declaration,       \         R (&funcPointer)(BOOST_PP_ENUM_PARAMS(n, T)) )// generate overloads for 0-9 paramatersBOOST_PP_REPEAT(10, GEN_OVERLOAD, ~)#undef GEN_OVERLOAD
I implemented Angelscript in my engine last week and did some macros for this.

#define ScriptFunction(returnType, function, usage) scriptEngine->RegisterGlobalFunction(#returnType" "#function#usage, asFUNCTION(function), asCALL_CDECL);


Example of usage:
// Define a functionint add(int x, int y){	return x + y;}int main(){	// Make function available from the script	ScriptFunction(int, add, "(int, int)");	return 0;}


I am not sure if it was exactly this way you use it. But you see the idea anyway. I also added support for member functions. You can look at my code here if you want to: http://openfury.svn.sourceforge.net/viewvc/openfury/trunk/include/engine/scriptmacros.h?view=markup
http://www.klarre.se
Oh ok i just read what Klarre wrote, if thats what you want then id utilize the type system.

// traits class to give the name of a type as a stringtemplate<typename T>struct script_func_traits{    static const char* type_name;};template<typename T>const char* script_func_traits<T>::type_name = typeid(T).name();// specialize for built in types and any classes you want to use#define SCRIPT_FUNC_TRAITS_SPECIALIZATION(type) \     template<>                                  \     struct script_func_traits<type>             \     {                                           \         static const char* type_name;           \     };                                          \                                                 \     template<>                                  \     const char* script_func_traits<type>::type_name = #typeSCRIPT_FUNC_TRAITS_SPECIALIZATION(int)SCRIPT_FUNC_TRAITS_SPECIALIZATION(unsigned int)SCRIPT_FUNC_TRAITS_SPECIALIZATION(char)SCRIPT_FUNC_TRAITS_SPECIALIZATION(long)// ...#undef SCRIPT_FUNC_TRAITS_SPECIALIZATION// function that takes the function name and function pointer and registers it#define GEN_REGISTER_FUNCTION(z, n, _)                                        \     template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(n, typename T)>         \     void register_function(const std::string& name,                           \                            R (&func)(BOOST_PP_ENUM_PARAMS(n, T)))             \     {                                                                         \         /* construct the prototype string "R name(T0, T1, ..., Tn)" */        \         std::string prototype = script_func_traits<R>::type_name +            \                             (" " + name) + "(" +                              \        BOOST_PP_ENUM_BINARY_PARAMS                                            \        (   n,                                                                 \            script_func_traits<T,>::type_name + "," + BOOST_PP_INTERCEPT       \        )                                                                      \                              ")";                                             \        r = engine->RegisterGlobalFunction(prototype.c_str(),                  \                                            asFUNCTION(func),                  \                                            asCALL_CDECL);                     \         assert( r >= 0 );                                                     \     }/* genrate overloads for functions with 0 - 9 paramaters */BOOST_PP_REPEAT(10, GEN_REGISTER_FUNCTION, ~)#undef GEN_REGISTER_FUNCTION/* utility macro */#define REGISTER_SCRIPT_FUNCTION(function) \     register_function(#function, function)


Edit: Fixed the errors Deyja mentioned. You might be able to overcome the differences in type names by editing SCRIPT_FUNC_TRAITS_SPECIALIZATION to take the name of the type in AngelScript but im not sure because ive never used it.

[Edited by - Julian90 on April 20, 2007 6:52:26 AM]
You should have posted this in the AngelScript forums.

Why, exactly, is invoking asFUNCTION so dreaded? This seems to be a lot of over-engineered fluff to avoid one little macro which you just end up invoking anyway. Julian90's implementation is interesting in that it seems to be building the signature string on the fly. Except that it doesn't put a space between the return type and the function name, and doesn't put any commas in the argument list. Unfortunately, it wouldn't work, because the names of AngelScript types aren't the same as the names in C++.
Quote:Do you want to be able to call any function, given only a pointer to the function (void* or whatever), and a variable argument list (So essentially make the call yourself)?

I think that kinda was the plan...somewhat combined with what Klarre is doing, but without macros.

Quote:You should have posted this in the AngelScript forums.

Sorry, I felt it was more suited to general programming as it is more of a programming question.

Quote:
Why, exactly, is invoking asFUNCTION so dreaded?

I have no idea! Actually I do - it isn't. I just thought it would be something cool to be able to do, but it appears pretty intense with *a lot* of overhead bloat, which I don't really want. I think I might just go with:

void TScript::ExposeFn( const std::string *declaration, const asUPtr &funcPointer )//call itscript->ExposeFn("int print(int, int)",asFUNCTION(myfn));


I would still be very interested in seeing evil steve's method. Is this the way that printf handles the multiple arguments?

PS. I'm sorry for my slight incoherence above. I guess it was just too early in the morning...

This topic is closed to new replies.

Advertisement