• Advertisement
Sign in to follow this  

Function Args & templates

This topic is 3872 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to set up some nicer script binding code for GM script using some template tricks, and while I don't fully understand the template tricks yet, I came across this link, first reply that shows some simple template code that can be used to extract the parameter types from a function passed in. I plugged this into my binding code and it works great, and I was able to do a big part of my binding code nicely in a form that emulates Squirrel. I've run into a roadblock however. This doesn't seem to be able to work getting the arguments of a member function. Taking the code from the link above, if you add
class MyTestClass
{
public:
void DoSomething() {}
}
and in main()
showtype(&MyClass::DoSomething);
I get the error 'void showtype(T *)' : could not deduce template argument for 'T *' from 'void (__thiscall MyTestClass::* )(int,float)' Obviously this is a member function pointer, and the code works if it were static, but I need to get arguments for it all the same. Anyone know how to get this working? While we're on the subject are there any other methods of doing this? Oddly, if I remove the * from the showtype definition, so it's just template<class T> void showtype(T t), it compiles, but the function traits then fail to resolve correctly. Any help or alternatives is greatly appreciated. Other than this it is working great for automatic binding code, such as this example
class MyTestClass
{
public:
	int myint;
	float myfloat;
	bool mybool;
	std::string mystring;

	void DoSomething(int p1, float p2) {}
	
	static void DoSomethingStatic0() {}
	static void DoSomethingStatic1(int p1) {}
	static void DoSomethingStatic2(int p1, float p2) {}
	static void DoSomethingStatic3(int p1, float p2, const char *p3) {}
	static void DoSomethingStatic4(bool p1, std::string p2) {}
private:
};

// And the bindings
gmMachine *pM = new gmMachine;
gmClass<MyTestClass>("MyTestClass", pM)
		.var(&MyTestClass::myint, "myint")
		.var(&MyTestClass::myfloat, "myfloat")
		.var(&MyTestClass::mybool, "mybool")
		.var(&MyTestClass::mystring, "mystring")
		//.func(&MyTestClass::DoSomething,"DoSomething") <-- this part no workie
		.staticfunc(&MyTestClass::DoSomethingStatic0, "Do0")
		.staticfunc(&MyTestClass::DoSomethingStatic1, "Do1")
		.staticfunc(&MyTestClass::DoSomethingStatic2, "Do2")
		.staticfunc(&MyTestClass::DoSomethingStatic3, "Do3")
		.staticfunc(&MyTestClass::DoSomethingStatic4, "Do4")
		;

Share this post


Link to post
Share on other sites
Advertisement
You need new specializations for member function pointers:

template<class R, class T> struct function_traits<R(T::*)(void)>
{
enum { numParams = 0 };
typedef R return_type;
};

and an overload for showType

template<class T, class T2> void showtype(T (T2::*t)(void))
{
typedef function_traits<T (T2::*)(void)> traits;
std::cout << "numParams: " << traits::numParams << std::endl;
std::cout << "return type: " << typeid(traits::return_type).name() << std::endl;
}

Share this post


Link to post
Share on other sites
You've only specialized it for function pointers, however, the type of a member function is different from that of a non-member functions so you need to add th extra specializations.


template<typname R, typename T>
void showtype(R (T::*fun)())
{
// ....
}

template<typename R, typename T, typename P0>
void showtype(R (T::*fun)(P0))
{
// ....
}



Also have a look at boost.type_traits and boost.preprocessor

Share this post


Link to post
Share on other sites
So for member functions you have to do a seperate one per # of arguments?

Share this post


Link to post
Share on other sites
Another question. Is there a way to do sort of conditional templates? I can handle the return type fine, but when I try to bind a void return type function it doesn't compile.

Share this post


Link to post
Share on other sites
To clarify the question, supposed I had my binding code resolve and end up calling the native function through a functor.

int operator()(ClassT *a_object,gmThread *a_thread)
{
GM_CHECK_NUM_PARAMS(numParams);
param1_type p1;
param2_type p2;

if(!ParamHelper(a_thread, 0, p1) || !ParamHelper(a_thread, 1, p2))
return GM_EXCEPTION;

(a_object->*m_Function)(p1,p2);
return GM_OK;
}


This works nicely, however, I'm not sure how to handle the return type. If I do this

int operator()(ClassT *a_object,gmThread *a_thread)
{
GM_CHECK_NUM_PARAMS(numParams);
param1_type p1;
param2_type p2;

if(!ParamHelper(a_thread, 0, p1) || !ParamHelper(a_thread, 1, p2))
return GM_EXCEPTION;

return_type r = (a_object->*m_Function)(p1,p2);
a_thread->Push(r);
return GM_OK;
}


This works great if all my functions are guaranteed a non void return type, so attempting to bind a function with a void return type will error for obvious reasons. Is there any more template magic to handle this sort of issue. I noticed the is_void<T> stuff in the boost type traits stuff, but I'm unsure how to use it to do what I'm wanting. Essentially I need to do an conditional on is_void<R> to pick two slightly different code snippets.

Share this post


Link to post
Share on other sites
Quote:
Original post by DrEvil
To clarify the question, supposed I had my binding code resolve and end up calling the native function through a functor.

int operator()(ClassT *a_object,gmThread *a_thread)
{
GM_CHECK_NUM_PARAMS(numParams);
param1_type p1;
param2_type p2;

if(!ParamHelper(a_thread, 0, p1) || !ParamHelper(a_thread, 1, p2))
return GM_EXCEPTION;

(a_object->*m_Function)(p1,p2);
return GM_OK;
}


This works nicely, however, I'm not sure how to handle the return type. If I do this

int operator()(ClassT *a_object,gmThread *a_thread)
{
GM_CHECK_NUM_PARAMS(numParams);
param1_type p1;
param2_type p2;

if(!ParamHelper(a_thread, 0, p1) || !ParamHelper(a_thread, 1, p2))
return GM_EXCEPTION;

return_type r = (a_object->*m_Function)(p1,p2);
a_thread->Push(r);
return GM_OK;
}


This works great if all my functions are guaranteed a non void return type, so attempting to bind a function with a void return type will error for obvious reasons. Is there any more template magic to handle this sort of issue. I noticed the is_void<T> stuff in the boost type traits stuff, but I'm unsure how to use it to do what I'm wanting. Essentially I need to do an conditional on is_void<R> to pick two slightly different code snippets.


If I understand your question correctly then a little template specialization should fix it. Something like:
template<typename R>
void do_something(R (*fn)() )
{
R ret = fn();
// Do some more.
}

// Specialize for R = void
template<>
void do_something(void (*fn)() )
{
fn();
// Do some more.
}

Share this post


Link to post
Share on other sites
try the functors and typelists from http://loki-lib.sourceforge.net/

While I try to steer clear of template black magic (meta programing).

Or have a look at what Lua Plus or squirrel plus do. (since they are template lib for exposing native code to script engines, that might be simmilar to what your doing. ;} )

They use a lot of specialisation.

The format your trying to use looks a lot like squirrel plus.

Share this post


Link to post
Share on other sites
Ugh, I was hoping not to have to dupe a bunch of code simply for void versions. This is what SqPlus does as well, but I had hoped there would be another way. Oh well it's a necessary evil I suppose.
That's quite a lot of duplication. Yes, the interface is heavily influenced/inspired by SqPlus. I prefer its simplicity over other binding interfaces that I've seen.

[Edited by - DrEvil on June 18, 2007 11:49:38 AM]

Share this post


Link to post
Share on other sites
Fair enough. SqPlus is quite clean all thing considered.
While I havn't looked into the required duplication, you could work some #include nastyness to do it for you.

Perhaps..

#define RETURN_TYPE void
#include "dupCode.inl"
#undef RETURN_TYPE

#define RETURN_TYPE typename
#include "dupCode.inl"
#undef RETURN_TYPE

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement