Jump to content
  • Advertisement
Sign in to follow this  
marshdabeachy

Storing function pointers

This topic is 3314 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 writing an input manager that will provide callbacks to other classes that register with it. The idea is that when, for example, you press 'a', every class that has registered with DIK_A will be notified. When registering, I pass in the instance of the class to notify, as well as the member function within the class to notify. I've got this part working. Looks like this:
template <class T>
void InputManager::RegisterKeyboardCallback(unsigned key, T* instance, void (T::*function)(float))
{
	// sample function call
	(*instance.*function)(1.0f);
}
However, the problem comes in storing this information. There doesn't seem to be a way, at least that I've figured out, to keep track of every instance/function that's registered inside of InputManager so when the key is actually pressed it can look up all of the instances/functions to call, simply because it's so generic. Any ideas?

Share this post


Link to post
Share on other sites
Advertisement
I used this article to help me implement a better functor class. I use it for the exact same thing in my editor application - registering for input commands. Since it's late, and I'm nice, I'll provide you the code for both my autogen script (in Python), and it's C++ output.

I have had a few problems with the outputted C++ with the SNC compiler (easily fixed but fixes aren't included here), but if you are using visual studio, it should be fine. It may not work straight off with GCC, haven't tried.


#=============================================
# Functor Generator
# Author: Neil Richardson
#=============================================

#=============================================
# Generate a seperated string based on a template.
# template could be "typename _P%NUM%" or something similar.
def genSeperatedString( range, template, seperator ):
outString = ""
for each in range:
if each != 0:
outString = outString + seperator
outString = outString + template.replace( "%NUM%", str( each ) )
return outString

#=============================================
# Generate a BcFuncTraits class
def BcFuncTraits_header( outFile ):
outFile.write( "//////////////////////////////////////////////////////////////////////////\n" )
outFile.write( "// BcFuncTraits\n\n" )
outFile.write( "template< typename _Fn >\n" )
outFile.write( "struct BcFuncTraits;\n\n" )

def BcFuncTraits_gen( outFile, numParams, isClass ):
outString = ""
if isClass == 0:
templateList = genSeperatedString( range( 0, numParams ), ", typename _P%NUM%", "" )
paramList = genSeperatedString( range( 0, numParams ), "_P%NUM%", ", " )
typedefList = genSeperatedString( range( 0, numParams ), "\ttypedef _P%NUM% param%NUM%_type;\n", "" )
outString += "template< typename _R" + templateList + " >\n"
outString += "struct BcFuncTraits< _R(*)(" + paramList + ") >\n"
outString += "{\n"
outString += " static const int PARAMS = " + str( numParams ) + ";\n"
outString += " typedef _R return_type;\n"
outString += typedefList
outString += " typedef _R(*signature_type)(" + paramList + ");\n"
outString += "};\n\n"
else:
templateList = genSeperatedString( range( 0, numParams ), ", typename _P%NUM%", "" )
paramList = genSeperatedString( range( 0, numParams ), "_P%NUM%", ", " )
typedefList = genSeperatedString( range( 0, numParams ), "\ttypedef _P%NUM% param%NUM%_type;\n", "" )
outString += "template< typename _Ty, typename _R" + templateList + " >\n"
outString += "struct BcFuncTraits< _R(_Ty::*)(" + paramList + ") >\n"
outString += "{\n"
outString += " static const int PARAMS = " + str( numParams ) + ";\n"
outString += " typedef _Ty class_type;\n"
outString += " typedef _R return_type;\n"
outString += typedefList
outString += " typedef _R(*signature_type)(" + paramList + ");\n"
outString += "};\n\n"
outFile.write( outString )

#=============================================
# Generate the functor.
def BcFunctor_header( outFile ):
outFile.write( "//////////////////////////////////////////////////////////////////////////\n" )
outFile.write( "// _BcFunctor\n\n" )
outFile.write( "template< typename _Fn, int >" )
outFile.write( "class _BcFunctor;" )

def BcFunctor_gen( outFile, numParams ):
outString = ""
typedefList = genSeperatedString( range( 0, numParams ), " typedef typename BcFuncTraits< _Fn >::param%NUM%_type param%NUM%_type;\n", "" )
paramList = genSeperatedString( range( 0, numParams ), "param%NUM%_type P%NUM%", ", " )
paramTypeList = genSeperatedString( range( 0, numParams ), "param%NUM%_type", ", " )
paramCallList = genSeperatedString( range( 0, numParams ), "P%NUM%", ", " )
outString += "template< typename _Fn >\n"
outString += "class _BcFunctor< _Fn, " + str( numParams ) + " >\n"
outString += "{\n"
outString += "public:\n"
outString += " typedef typename _BcFunctor< _Fn, " + str( numParams ) + " > this_type;\n"
outString += " typedef typename BcFuncTraits< _Fn >::return_type return_type;\n"
outString += typedefList
if numParams == 0:
outString += " typedef typename return_type(*stub_func)(void*);\n"
else:
outString += " typedef typename return_type(*stub_func)(void*,"+paramTypeList+");\n"
outString += "public:\n"

outString += " BcForceInline _BcFunctor(): pThis_( NULL ), stubFunc_( NULL ){};\n"


outString += " BcForceInline return_type operator()(" + paramList + ")\n"
outString += " {\n"
outString += " BcAssert( stubFunc_ != NULL );\n"
if numParams == 0:
outString += " return (*stubFunc_)(pThis_);\n"
else:
outString += " return (*stubFunc_)(pThis_, " + paramCallList + ");\n"
outString += " }\n\n"

outString += " BcForceInline BcBool isValid() const\n"
outString += " {\n"
outString += " return ( stubFunc_ != NULL )\n"
outString += " }\n\n"

outString += " template< _Fn _func >\n"
outString += " static this_type bind()\n"
outString += " {\n"
outString += " this_type Func;\n"
outString += " Func.pThis_ = NULL;\n"
outString += " Func.stubFunc_ = &global_stub< _func >;\n"
outString += " return Func;\n"
outString += " }\n\n"

outString += " template< class _Ty, return_type(_Ty::*_func)("+paramTypeList+") >\n"
outString += " static this_type bind( _Ty* pThis )\n"
outString += " {\n"
outString += " this_type Func;\n"
outString += " Func.pThis_ = pThis;\n"
outString += " Func.stubFunc_ = &method_stub< _Ty, _func >;\n"
outString += " BcAssert( pThis != NULL );\n"
outString += " return Func;\n"
outString += " }\n\n"

outString += "private:\n"
outString += " template< _Fn func >\n"
if numParams == 0:
outString += " static return_type global_stub( void* )\n"
else:
outString += " static return_type global_stub( void*, " + paramList + " )\n"
outString += " {\n"
outString += " return (*func)( " + paramCallList + " );\n"
outString += " }\n\n"

outString += " template< class _Ty, return_type (_Ty::*meth)("+paramTypeList+") >\n"
if numParams == 0:
outString += " static return_type method_stub( void* )\n"
else:
outString += " static return_type method_stub( void* pObj, " + paramList + " )\n"
outString += " {\n"
outString += " _Ty* pThis = static_cast< _Ty* >( pObj );\n"
outString += " return (pThis->*meth)( " + paramCallList + " );\n"
outString += " }\n\n"
outString += "private:\n"
outString += " void* pThis_;\n"
outString += " stub_func stubFunc_;\n"
outString += "};\n\n"
outFile.write( outString )

def BcFunctor_footer( outFile ):
outString = ""
outString += "template< typename _Fn >\n"
outString += "struct BcFunctor\n"
outString += "{\n"
outString += " typedef typename _BcFunctor< _Fn, BcFuncTraits< _Fn >::PARAMS > type;\n"
outString += "};\n";
outFile.write( outString )

#=============================================
# Generate the functor file.
outFile = open( "BcFunctor.h", "w+" )


outString = ""
outString += "/**************************************************************************\n"
outString += "*\n"
outString += "* File: BcFunctor.h\n"
outString += "* Author: Neil Richardson & Autogeneration Script\n"
outString += "* Ver/Date:\n"
outString += "* Description:\n"
outString += "* Function object.\n"
outString += "*\n"
outString += "*\n"
outString += "*\n"
outString += "**************************************************************************/\n\n"
outString += "#ifndef __BCFUNCTOR_H__\n"
outString += "#define __BCFUNCTOR_H__\n\n"
outString += "#include \"BcTypes.h\"\n\n"
outFile.write( outString )

numParams = 5

BcFuncTraits_header( outFile )
for each in range( 0, numParams ):
BcFuncTraits_gen( outFile, each, 0 )
for each in range( 0, numParams ):
BcFuncTraits_gen( outFile, each, 1 )

BcFunctor_header( outFile )
for each in range( 0, numParams ):
BcFunctor_gen( outFile, each )

BcFunctor_footer( outFile )

outString = ""
outString += "#endif\n"
outFile.write( outString )







/**************************************************************************
*
* File: BcFunctor.h
* Author: Neil Richardson & Autogeneration Script
* Ver/Date:
* Description:
* Function object.
*
*
*
**************************************************************************/


#ifndef __BCFUNCTOR_H__
#define __BCFUNCTOR_H__

#include "BcTypes.h"

//////////////////////////////////////////////////////////////////////////
// BcFuncTraits

template< typename _Fn >
struct BcFuncTraits;

template< typename _R >
struct BcFuncTraits< _R(*)() >
{
static const int PARAMS = 0;
typedef _R return_type;
typedef _R(*signature_type)();
};

template< typename _R, typename _P0 >
struct BcFuncTraits< _R(*)(_P0) >
{
static const int PARAMS = 1;
typedef _R return_type;
typedef _P0 param0_type;
typedef _R(*signature_type)(_P0);
};

template< typename _R, typename _P0, typename _P1 >
struct BcFuncTraits< _R(*)(_P0, _P1) >
{
static const int PARAMS = 2;
typedef _R return_type;
typedef _P0 param0_type;
typedef _P1 param1_type;
typedef _R(*signature_type)(_P0, _P1);
};

template< typename _R, typename _P0, typename _P1, typename _P2 >
struct BcFuncTraits< _R(*)(_P0, _P1, _P2) >
{
static const int PARAMS = 3;
typedef _R return_type;
typedef _P0 param0_type;
typedef _P1 param1_type;
typedef _P2 param2_type;
typedef _R(*signature_type)(_P0, _P1, _P2);
};

template< typename _R, typename _P0, typename _P1, typename _P2, typename _P3 >
struct BcFuncTraits< _R(*)(_P0, _P1, _P2, _P3) >
{
static const int PARAMS = 4;
typedef _R return_type;
typedef _P0 param0_type;
typedef _P1 param1_type;
typedef _P2 param2_type;
typedef _P3 param3_type;
typedef _R(*signature_type)(_P0, _P1, _P2, _P3);
};

template< typename _Ty, typename _R >
struct BcFuncTraits< _R(_Ty::*)() >
{
static const int PARAMS = 0;
typedef _Ty class_type;
typedef _R return_type;
typedef _R(*signature_type)();
};

template< typename _Ty, typename _R, typename _P0 >
struct BcFuncTraits< _R(_Ty::*)(_P0) >
{
static const int PARAMS = 1;
typedef _Ty class_type;
typedef _R return_type;
typedef _P0 param0_type;
typedef _R(*signature_type)(_P0);
};

template< typename _Ty, typename _R, typename _P0, typename _P1 >
struct BcFuncTraits< _R(_Ty::*)(_P0, _P1) >
{
static const int PARAMS = 2;
typedef _Ty class_type;
typedef _R return_type;
typedef _P0 param0_type;
typedef _P1 param1_type;
typedef _R(*signature_type)(_P0, _P1);
};

template< typename _Ty, typename _R, typename _P0, typename _P1, typename _P2 >
struct BcFuncTraits< _R(_Ty::*)(_P0, _P1, _P2) >
{
static const int PARAMS = 3;
typedef _Ty class_type;
typedef _R return_type;
typedef _P0 param0_type;
typedef _P1 param1_type;
typedef _P2 param2_type;
typedef _R(*signature_type)(_P0, _P1, _P2);
};

template< typename _Ty, typename _R, typename _P0, typename _P1, typename _P2, typename _P3 >
struct BcFuncTraits< _R(_Ty::*)(_P0, _P1, _P2, _P3) >
{
static const int PARAMS = 4;
typedef _Ty class_type;
typedef _R return_type;
typedef _P0 param0_type;
typedef _P1 param1_type;
typedef _P2 param2_type;
typedef _P3 param3_type;
typedef _R(*signature_type)(_P0, _P1, _P2, _P3);
};

//////////////////////////////////////////////////////////////////////////
// _BcFunctor

template< typename _Fn, int >class _BcFunctor;template< typename _Fn >
class _BcFunctor< _Fn, 0 >
{
public:
typedef typename _BcFunctor< _Fn, 0 > this_type;
typedef typename BcFuncTraits< _Fn >::return_type return_type;
typedef typename return_type(*stub_func)(void*);
public:
BcForceInline _BcFunctor(): pThis_( NULL ), stubFunc_( NULL ){};
BcForceInline return_type operator()()
{
BcAssert( stubFunc_ != NULL );
return (*stubFunc_)(pThis_);
}

BcForceInline BcBool isValid() const
{
return ( stubFunc_ != NULL )
}

template< _Fn _func >
static this_type bind()
{
this_type Func;
Func.pThis_ = NULL;
Func.stubFunc_ = &global_stub< _func >;
return Func;
}

template< class _Ty, return_type(_Ty::*_func)() >
static this_type bind( _Ty* pThis )
{
this_type Func;
Func.pThis_ = pThis;
Func.stubFunc_ = &method_stub< _Ty, _func >;
BcAssert( pThis != NULL );
return Func;
}

private:
template< _Fn func >
static return_type global_stub( void* )
{
return (*func)( );
}

template< class _Ty, return_type (_Ty::*meth)() >
static return_type method_stub( void* )
{
_Ty* pThis = static_cast< _Ty* >( pObj );
return (pThis->*meth)( );
}

private:
void* pThis_;
stub_func stubFunc_;
};

template< typename _Fn >
class _BcFunctor< _Fn, 1 >
{
public:
typedef typename _BcFunctor< _Fn, 1 > this_type;
typedef typename BcFuncTraits< _Fn >::return_type return_type;
typedef typename BcFuncTraits< _Fn >::param0_type param0_type;
typedef typename return_type(*stub_func)(void*,param0_type);
public:
BcForceInline _BcFunctor(): pThis_( NULL ), stubFunc_( NULL ){};
BcForceInline return_type operator()(param0_type P0)
{
BcAssert( stubFunc_ != NULL );
return (*stubFunc_)(pThis_, P0);
}

BcForceInline BcBool isValid() const
{
return ( stubFunc_ != NULL )
}

template< _Fn _func >
static this_type bind()
{
this_type Func;
Func.pThis_ = NULL;
Func.stubFunc_ = &global_stub< _func >;
return Func;
}

template< class _Ty, return_type(_Ty::*_func)(param0_type) >
static this_type bind( _Ty* pThis )
{
this_type Func;
Func.pThis_ = pThis;
Func.stubFunc_ = &method_stub< _Ty, _func >;
BcAssert( pThis != NULL );
return Func;
}

private:
template< _Fn func >
static return_type global_stub( void*, param0_type P0 )
{
return (*func)( P0 );
}

template< class _Ty, return_type (_Ty::*meth)(param0_type) >
static return_type method_stub( void* pObj, param0_type P0 )
{
_Ty* pThis = static_cast< _Ty* >( pObj );
return (pThis->*meth)( P0 );
}

private:
void* pThis_;
stub_func stubFunc_;
};

template< typename _Fn >
class _BcFunctor< _Fn, 2 >
{
public:
typedef typename _BcFunctor< _Fn, 2 > this_type;
typedef typename BcFuncTraits< _Fn >::return_type return_type;
typedef typename BcFuncTraits< _Fn >::param0_type param0_type;
typedef typename BcFuncTraits< _Fn >::param1_type param1_type;
typedef typename return_type(*stub_func)(void*,param0_type, param1_type);
public:
BcForceInline _BcFunctor(): pThis_( NULL ), stubFunc_( NULL ){};
BcForceInline return_type operator()(param0_type P0, param1_type P1)
{
BcAssert( stubFunc_ != NULL );
return (*stubFunc_)(pThis_, P0, P1);
}

BcForceInline BcBool isValid() const
{
return ( stubFunc_ != NULL )
}

template< _Fn _func >
static this_type bind()
{
this_type Func;
Func.pThis_ = NULL;
Func.stubFunc_ = &global_stub< _func >;
return Func;
}

template< class _Ty, return_type(_Ty::*_func)(param0_type, param1_type) >
static this_type bind( _Ty* pThis )
{
this_type Func;
Func.pThis_ = pThis;
Func.stubFunc_ = &method_stub< _Ty, _func >;
BcAssert( pThis != NULL );
return Func;
}

private:
template< _Fn func >
static return_type global_stub( void*, param0_type P0, param1_type P1 )
{
return (*func)( P0, P1 );
}

template< class _Ty, return_type (_Ty::*meth)(param0_type, param1_type) >
static return_type method_stub( void* pObj, param0_type P0, param1_type P1 )
{
_Ty* pThis = static_cast< _Ty* >( pObj );
return (pThis->*meth)( P0, P1 );
}

private:
void* pThis_;
stub_func stubFunc_;
};

template< typename _Fn >
class _BcFunctor< _Fn, 3 >
{
public:
typedef typename _BcFunctor< _Fn, 3 > this_type;
typedef typename BcFuncTraits< _Fn >::return_type return_type;
typedef typename BcFuncTraits< _Fn >::param0_type param0_type;
typedef typename BcFuncTraits< _Fn >::param1_type param1_type;
typedef typename BcFuncTraits< _Fn >::param2_type param2_type;
typedef typename return_type(*stub_func)(void*,param0_type, param1_type, param2_type);
public:
BcForceInline _BcFunctor(): pThis_( NULL ), stubFunc_( NULL ){};
BcForceInline return_type operator()(param0_type P0, param1_type P1, param2_type P2)
{
BcAssert( stubFunc_ != NULL );
return (*stubFunc_)(pThis_, P0, P1, P2);
}

BcForceInline BcBool isValid() const
{
return ( stubFunc_ != NULL )
}

template< _Fn _func >
static this_type bind()
{
this_type Func;
Func.pThis_ = NULL;
Func.stubFunc_ = &global_stub< _func >;
return Func;
}

template< class _Ty, return_type(_Ty::*_func)(param0_type, param1_type, param2_type) >
static this_type bind( _Ty* pThis )
{
this_type Func;
Func.pThis_ = pThis;
Func.stubFunc_ = &method_stub< _Ty, _func >;
BcAssert( pThis != NULL );
return Func;
}

private:
template< _Fn func >
static return_type global_stub( void*, param0_type P0, param1_type P1, param2_type P2 )
{
return (*func)( P0, P1, P2 );
}

template< class _Ty, return_type (_Ty::*meth)(param0_type, param1_type, param2_type) >
static return_type method_stub( void* pObj, param0_type P0, param1_type P1, param2_type P2 )
{
_Ty* pThis = static_cast< _Ty* >( pObj );
return (pThis->*meth)( P0, P1, P2 );
}

private:
void* pThis_;
stub_func stubFunc_;
};

template< typename _Fn >
class _BcFunctor< _Fn, 4 >
{
public:
typedef typename _BcFunctor< _Fn, 4 > this_type;
typedef typename BcFuncTraits< _Fn >::return_type return_type;
typedef typename BcFuncTraits< _Fn >::param0_type param0_type;
typedef typename BcFuncTraits< _Fn >::param1_type param1_type;
typedef typename BcFuncTraits< _Fn >::param2_type param2_type;
typedef typename BcFuncTraits< _Fn >::param3_type param3_type;
typedef typename return_type(*stub_func)(void*,param0_type, param1_type, param2_type, param3_type);
public:
BcForceInline _BcFunctor(): pThis_( NULL ), stubFunc_( NULL ){};
BcForceInline return_type operator()(param0_type P0, param1_type P1, param2_type P2, param3_type P3)
{
BcAssert( stubFunc_ != NULL );
return (*stubFunc_)(pThis_, P0, P1, P2, P3);
}

BcForceInline BcBool isValid() const
{
return ( stubFunc_ != NULL )
}

template< _Fn _func >
static this_type bind()
{
this_type Func;
Func.pThis_ = NULL;
Func.stubFunc_ = &global_stub< _func >;
return Func;
}

template< class _Ty, return_type(_Ty::*_func)(param0_type, param1_type, param2_type, param3_type) >
static this_type bind( _Ty* pThis )
{
this_type Func;
Func.pThis_ = pThis;
Func.stubFunc_ = &method_stub< _Ty, _func >;
BcAssert( pThis != NULL );
return Func;
}

private:
template< _Fn func >
static return_type global_stub( void*, param0_type P0, param1_type P1, param2_type P2, param3_type P3 )
{
return (*func)( P0, P1, P2, P3 );
}

template< class _Ty, return_type (_Ty::*meth)(param0_type, param1_type, param2_type, param3_type) >
static return_type method_stub( void* pObj, param0_type P0, param1_type P1, param2_type P2, param3_type P3 )
{
_Ty* pThis = static_cast< _Ty* >( pObj );
return (pThis->*meth)( P0, P1, P2, P3 );
}

private:
void* pThis_;
stub_func stubFunc_;
};

template< typename _Fn >
struct BcFunctor
{
typedef typename _BcFunctor< _Fn, BcFuncTraits< _Fn >::PARAMS > type;
};
#endif






Basic usage would be like this:


typedef BcFunctor< void(*)(float) >::type TKeyboardCallback;

InputManager::RegisterKeyboardCallback( VK_LEFT, TKeyboardCallback::bind< ClassName, &ClassName::methodName >( pInstanceOfClass ) );


with InputManager::RegisterKeyboardCallback declared as:


void InputManager::RegisterKeyboardCallback(unsigned key, TKeyboardCallback Callback );


Callback can be copied about, stored in a container, whatever, and then called later like:


Callback( floatParam );


Sorry for the immensely brief run through, but I'm just about to goto bed, feel free to take and use the code given - though it might be more use as reference, and you implement yourself [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by marshdabeachy
Thanks Richy, that looks like it will work. It'll take me a bit to go through everything though.

Out of curiosity, can you provide BcTypes.h?


All it is a bunch of typedefs, this should cover what's used in that code:


typedef unsigned _int64 BcU64;
typedef unsigned int BcU32;
typedef unsigned short BcU16;
typedef unsigned char BcU8;

typedef signed _int64 BcS64;
typedef signed int BcS32;
typedef signed short BcS16;
typedef signed char BcS8;

typedef float BcF32;
typedef double BcF64;
typedef float BcReal;
typedef char BcChar;
typedef bool BcBool;

typedef std::size_t BcSize;

#define BcTrue BcBool( true )
#define BcFalse BcBool( false )
#define BcBreakpoint __asm { int 3h }
#define BcErrorCode 0xffffffff
#define BcLogWrite( t )
#define BcUnusedVar( t ) (void)t

#define BcAlign( t ) _declspec(align(t))
#define BcInline inline
#define BcForceInline __forceinline

Share this post


Link to post
Share on other sites
Quote:
Original post by bobofjoe
If you're using C++; there is next to no reason not to use boost::function and boost::bind


Reason I didn't suggest that first (was initially the solution for me), was because I successfully crashed the VS2008 compiler with it. I'd still second this and suggest using boost though, it's a good thing to learn.

Share this post


Link to post
Share on other sites
For that matter, any discussion of "registering callbacks" in C++ should really mention boost::signals.


boost::signal<void(float)> OnKeyA;

void handleKey(float baz)
{
...
}

MyClass foo;

OnKeyA.connect(boost::bind(&MyClass::ACallback, foo, _1));
OnKeyA.connect(&handleKey);
...

OnKeyA(3.0f); // calls foo.ACallback(3.0f) and handleKey(3.0f)

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!