我正在尝试编写一个接受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:错误:没有匹配函数来调用
CallFunc(unsigned int&, unsigned int&, void (&)(unsigned int, unsigned int))
如果我显式创建了一个正确类型的std :: function(或者把它强制转换),问题就会消失:
std::function< void ( unsigned, unsigned ) > func( DoSomething );
CallFunc( id, param, func );
我如何对此进行编码,以便不需要显式临时?
答案 0 :(得分:8)
您需要将第三个函数参数作为其中模板参数的非推导上下文。然后编译器不会将参数类型与参数类型进行比较而不考虑所有隐式转换(标准说明,并且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 );
}
您可以使用id
代替boost::identity
。在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尚不支持别名模板。
答案 1 :(得分:2)
如果您使用模板,则可以完全避免使用std::function
,除非出于某种原因您想要明确限制功能std::function
:
template < typename Ident, typename Param, typename Func >
void CallFunc( Ident ident, Param param, Func op )
{
op( ident, param );
}
答案 2 :(得分:0)
您可以进行内联转换或使用:bind
。两者都不是特别漂亮,但他们完成了工作
CallFunc(id, param, std::function<void(unsigned, unsigned)>(DoSomething));
CallFunc(id, param, std::bind(DoSomething, std::placeholders::_1, std::placeholders::_2));