我有这个问题困扰我.我有FSM类,它将键与回调相关联
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;
};
Run Code Online (Sandbox Code Playgroud)
还有一些回调类
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;
}
};
Run Code Online (Sandbox Code Playgroud)
现在,如果进入主要我做:
FSM aFSM;
// OK
aFSM.addCallback( "one", &FSM::callback< CallbackBase, &CallbackBase::operator() > );
// KO
aFSM.addCallback( "two", &FSM::callback< Callback, &Callback::operator() > );
Run Code Online (Sandbox Code Playgroud)
第一个调用很好,在第二个编译器抱怨:
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’
Run Code Online (Sandbox Code Playgroud)
另请注意以下情况
typedef bool (Callback::*Function_t)( int );
Function_t aFunction = &Callback::operator();
(Callback().*aFunction)( 5 );
Run Code Online (Sandbox Code Playgroud)
任何的想法?在此先感谢您的帮助.
西蒙娜
您尚未定义 Callback::operator()。Callback 没有第二个函数,只有 CallbackBase 中的函数,它接受 CallbackBase 和 int 作为参数!这就是编译器抱怨“未解析的重载函数类型”的原因。
继承的函数类型为bool(CallbackBase::*operator())(int)。该函数可以自动转换为 bool (Callback::*operator())(int),因为您始终可以将 Callback 应用于仅接受 CallbackBase 的函数。这就是以下内容起作用的原因 - 这是那里发生的自动转换。
typedef bool (Callback::*Function_t)( int );
Function_t aFunction = &Callback::operator();
Run Code Online (Sandbox Code Playgroud)
问题发生在模板类型推导上:
template< typename Callback_t, bool (Callback_t::*CallbackFunct_t)(int) >
with: Callback_t = Callback, CallbackFunct_t = bool (CallbackBase::*CallbackFunct_t)(int)
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为在实例化回调函数时,通过 Callback_t 给出的类型和函数指针所需的类型不匹配。您可以通过在类型推导发生之前将函数指针显式转换为 (Callback::*operator())(int) 来解决该问题。如果将回调函数更改为以下内容,则不需要两种类型相同,并且无需强制转换即可编译。
template< typename Callback_t>
bool callback( int x )
{
return Callback_t()( x );
}
Run Code Online (Sandbox Code Playgroud)
我不明白的是为什么要添加虚函数。下面的代码不是会做同样的事情,更简单、更易读、甚至更快(没有虚函数调用)吗?doCall 函数需要是公共的。
template< typename Callback_t>
bool callback( int x )
{
return Callback_t().doCall( x );
}
Run Code Online (Sandbox Code Playgroud)
另一个改进是使回调函数静态。如果 doCall 函数是静态的,那就更简单了 - 这将使回调函数过时,并且可以避免创建一个临时函数来调用 doCall。