Functions as template parameters

I have this problem bothering me. I have an FSM class that associates keys with callbacks

class FSM { public: typedef bool (FSM::*InCallback_t)( int ); typedef std::map< std::string, InCallback_t > Table; // Since I would like to allow the user to register both functors and class member functions template< typename Callback_t, bool (Callback_t::*CallbackFunct_t)(int) > bool callback( int x ) { return (Callback_t().*CallbackFunct_t)( x ); } void addCallback( const std::string& iKey, InCallback_t iCallback ) { _table.insert( std::make_pair( iKey, iCallback ) ); } [ ... ] private: Table _table; }; 

And some callback classes

 class CallbackBase { public: bool operator()( int x ){ return doCall( x ); } private: virtual bool doCall( int x ){ return true; } }; class Callback: public CallbackBase { private: bool doCall( int x ) { std::cout << "Callback\n"; return true; } }; 

Now, if I basically do:

 FSM aFSM; // OK aFSM.addCallback( "one", &FSM::callback< CallbackBase, &CallbackBase::operator() > ); // KO aFSM.addCallback( "two", &FSM::callback< Callback, &Callback::operator() > ); 

The first call is fine, in the second the compiler complains:

 Test.cpp: In function 'int main(int, char**)': Test.cpp:104:77: error: no matching function for call to 'FSM::addCallback(const char [4], <unresolved overloaded function type>)' Test.cpp:104:77: note: candidate is: Test.cpp:24:7: note: void FSM::addCallback(const string&, FSM::InCallback_t) Test.cpp:24:7: note: no known conversion for argument 2 from '<unresolved overloaded function type>' to 'FSM::InCallback_t' 

Also note the following:

 typedef bool (Callback::*Function_t)( int ); Function_t aFunction = &Callback::operator(); (Callback().*aFunction)( 5 ); 

Any idea? Thanks in advance for your help.

Simone

+7
source share
1 answer

You did not define Callback :: operator (). There is no callback function for the callback function that takes CallbackBase and int as parameters! This is why the compiler groans about the "unsolved overloaded function type."

The type of the inherited function is bool (CallbackBase :: * operator ()) (int). This function can be automatically converted to bool (Callback :: * operator ()) (int), because you can always apply a callback to a function that accepts only CallbackBase. That is why the following work is an automatic throw taking place there.

 typedef bool (Callback::*Function_t)( int ); Function_t aFunction = &Callback::operator(); 

The problem arises with template type inference:

 template< typename Callback_t, bool (Callback_t::*CallbackFunct_t)(int) > with: Callback_t = Callback, CallbackFunct_t = bool (CallbackBase::*CallbackFunct_t)(int) 

This does not work because the types specified with Callback_t and the type required by the function pointer do not match if the callback function is initiated. You can solve the problem of explicitly casting a function pointer to (Callback :: * operator ()) (int) before type deduction occurs. If you change the callback function to the following, you do not require the two types to be identical, and they compile without a cast.

 template< typename Callback_t> bool callback( int x ) { return Callback_t()( x ); } 

I do not understand why you are adding a virtual function. Won't the following do the same, be simpler and more readable, and even faster (without calling virtual functions)? The doCall function must be public.

 template< typename Callback_t> bool callback( int x ) { return Callback_t().doCall( x ); } 

Another improvement is to make the callback function static. It would be even simpler if the doCall functions were static - this would make the callback function obsolete and prevent a temporary doCall call from being created.

+2
source

All Articles