The following code just wouldn't compile:
template< typename Fn >
bool templateFunctionOne( Fn&& fn )
{
int v = 5;
return fn( v );
}
template < typename Fn >
bool templateFunctionTwo( Fn&& fn )
{
std::future< bool > tk( std::async( std::launch::async,
&templateFunctionOne< Fn >,
std::forward<Fn>(fn ) ) );
return tk.get();
}
bool printThis( int value )
{
cout << value << endl;
return true;
}
int main()
{
auto func = std::bind( &printThis, std::placeholders::_1 );
return templateFunctionTwo( func );
}
when compiling it gives the following error:
functional::1665:61: error: no type named 'type' in 'class std::result_of< bool ((std::_Bind(std::_Placeholder<1>))(int)>))(std::_Bind))(int)>&)>'
I simplified the above, still it won't compile with the same error message:
template< typename Fn >
bool templateFunctionOne( Fn&& fn )
{
return fn();
}
template < typename Fn >
bool templateFunctionTwo( Fn&& fn )
{
std::future< bool > tk( std::async( std::launch::async,
&templateFunctionOne< Fn >,
std::forward<Fn>(fn ) ) );
return tk.get();
}
bool printThis()
{
return true;
}
int main()
{
auto func = std::bind( &printThis );
return templateFunctionTwo( func );
}
Since now the function printThis
doesn't require passing in any parameters, binding the call isn't necessary. And when changing the call in the main as follows, it compiles fine:
int main()
{
return templateFunctionTwo( &printThis );
}
Could someone help to explain? I've seen the same kind of errors when passing a function pointer without using std::ref
to wrap a parameter when its reference is required, but this seems to be something else (or not), what am I missing here?
auto func = std::bind( &printThis );
return templateFunctionTwo( func );
func
is Lvalue, so when Lvalue is passed into templateFunctionTwo
, Fn
is deduced to be Fn&
(due to forwarding reference).
Below line
&templateFunctionOne< Fn >,
means
&templateFunctionOne< Fn& >,
it implies that templateFunctionOne
takes its argument by reference,
if you want to pass argument by reference when calling async
you need to use wrapper std::ref
or std::cref
:
std::future< bool > tk = std::async(
templateFunctionOne< Fn >,
std::ref( std::forward<Fn>(fn) ) ); // <--- ref added
Now your code compiles.
Another way is to use remove_reference_t<Fn>
or
typename std::remove_reference<Fn>::type
to remove Lvalue reference from Fn
:
std::future< bool > tk = std::async(
templateFunctionOne< std::remove_reference_t<Fn> >, // <--- remove_reference_t added
std::forward<Fn>(fn) );
return tk.get();
then fn
object is passed by value. This version is better than first, because the call
templateFunctionTwo( std::bind( &printThis, std::placeholders::_1 ) )
fails when ref
is used, because ref
needs to take only Lvalues.