I am trying to write a template function that accepts a std::function
which depends on the template arguments. Unfortunately the compiler is not capable of correctly deucing the arguments to the std::function
. Here some simple example code:
#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;
}
If I call the template with the following:
CallFunc( id, param, DoSomething );
I get the following errors:
function-tpl.cpp:25: error: no matching function for call to
CallFunc(unsigned int&, unsigned int&, void (&)(unsigned int, unsigned int))
If I explicitly create a std::function of the correct type (or cast it) the problem goes away:
std::function< void ( unsigned, unsigned ) > func( DoSomething );
CallFunc( id, param, func );
How would I code this so that the explicit temporary is not needed?
You can do the conversion inline
or use:bind
. Neither is particularly pretty, but they get the job doneIf you are using templates, you can avoid
std::function
entirely, unless for some reason you want to specifically restrict the function to takestd::function
:You need to make the third function parameter a non-deduced context for the template parameters therein. Then the compiler will not compare the argument type against the parameter type without also considering all implicit conversions (the Standard says, and C++0x clarified this further, that for a function parameter where there are no template parameters in deducing positions, all implicit conversions are allowed in bridging a difference).
Instead of
id
you can useboost::identity
. In C++0x and compilers that support it, you can have a more readable edition using alias templatesThen your code becomes simply
However GCC does not yet support alias templates.