我正在尝试编写一个接受依赖于模板参数的 std::function
的模板函数。不幸的是,编译器无法正确推导出 std::function
的参数。这里有一些简单的示例代码:
#include <iostream>
#include <functional>
using namespace std;
void DoSomething( unsigned ident, unsigned param )
{
cout << "DoSomething called, ident = " << ident << ", param = " << param << "\n";
}
template < typename Ident, typename Param >
void CallFunc( Ident ident, Param param, std::function< void ( Ident, Param ) > op )
{
op( ident, param );
}
int main()
{
unsigned id(1);
unsigned param(1);
// The following fails to compile
// CallFunc( id, param, DoSomething );
// this is ok
std::function< void ( unsigned, unsigned ) > func( DoSomething );
CallFunc( id, param, func );
return 0;
}
如果我使用以下内容调用模板:
CallFunc( id, param, DoSomething );
我收到以下错误:
function-tpl.cpp:25: error: no matching function for call to
CallFunc(unsigned int&, unsigned int&, void (&)(unsigned int, unsigned int))
如果我显式地创建一个正确类型的 std::function(或转换它),问题就会消失:
std::function< void ( unsigned, unsigned ) > func( DoSomething );
CallFunc( id, param, func );
我将如何编写代码以便不需要显式临时文件?
最佳答案
您需要使第三个函数参数成为其中模板参数的非推导上下文。那么编译器将不会在不考虑所有隐式转换的情况下将参数类型与参数类型进行比较(标准说,C++0x 进一步澄清了这一点,对于在推导位置没有模板参数的函数参数,所有隐式允许转换以弥合差异)。
template < typename T > struct id { typedef T type; };
template < typename Ident, typename Param >
void CallFunc( Ident ident, Param param,
typename id<std::function< void ( Ident, Param ) >>::type op )
{
op( ident, param );
}
您可以使用 boost::identity
而不是 id
。在 C++0x 和支持它的编译器中,您可以使用别名模板获得更具可读性的版本
template < typename T > using nondeduced = typename id<T>::type;
那么你的代码就变得简单了
template < typename Ident, typename Param >
void CallFunc( Ident ident, Param param,
std::function< nondeduced<void ( Ident, Param )> > op )
{
op( ident, param );
}
但是 GCC 还不支持别名模板。
关于采用依赖于模板参数的 std::function 的 C++11 模板函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7608741/