Reputation: 115
I have this problem bothering me. I have the FSM class which associate keys to 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 callbacks 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 into the main I 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 one 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 notice that the following is fine
typedef bool (Callback::*Function_t)( int );
Function_t aFunction = &Callback::operator();
(Callback().*aFunction)( 5 );
Any idea? Thanks in advance for your help.
Simone
Upvotes: 7
Views: 1306
Reputation: 2787
You haven't defined Callback::operator(). There is no secound function for Callback just the function from CallbackBase which takes a CallbackBase and a int as parameters! This is why the compiler moans about "unresolved overloaded function type".
The type of the inherited function is bool (CallbackBase::*operator())(int). This function can be automatically converted to a bool (Callback::*operator())(int) because you can always apply a Callback to a function that accepts only a CallbackBase. This is the reason why the following works - it's a automatic cast happening there.
typedef bool (Callback::*Function_t)( int );
Function_t aFunction = &Callback::operator();
The problem happens with the template type deduction:
template< typename Callback_t, bool (Callback_t::*CallbackFunct_t)(int) >
with: Callback_t = Callback, CallbackFunct_t = bool (CallbackBase::*CallbackFunct_t)(int)
This doesn't work since the types that given via Callback_t and the type required by the function pointer do not match when instanciating the callback function. You can resolve the problem with a explicit cast of the function pointer to (Callback::*operator())(int) before the type deduction takes place. If you change the callback function to the following you do not require the two types to be identical and it compiles without the cast.
template< typename Callback_t>
bool callback( int x )
{
return Callback_t()( x );
}
What I don't understand is why you add the virtual function. Wouldn't the following do the same, be more simple and readable and even faster (no virtual function call)? The doCall function would be required to be public.
template< typename Callback_t>
bool callback( int x )
{
return Callback_t().doCall( x );
}
Another improvement would be to make the callback function static. It would be even more simple if the doCall functions would be static - this would make the callback function obsolete and would avoid creating a temporary to call doCall.
Upvotes: 2