以下代码无法编译:

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 );
 }

编译时出现以下错误:



我简化了上面的内容,但仍然无法使用相同的错误消息进行编译:
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 );
 }

由于现在函数printThis不需要传递任何参数,因此不需要绑定(bind)调用。并且当按如下方式更改主调用时,它可以正常编译:
 int main()
 {
    return templateFunctionTwo( &printThis );
 }

有人可以帮忙解释一下吗?在传递函数指针而不需要引用时不使用std::ref来包装参数时,我已经看到了相同类型的错误,但这似乎是其他事情(或没有),我在这里遗漏了什么?

最佳答案

auto func = std::bind( &printThis );
return templateFunctionTwo( func );
func是Lvalue,因此当Lvalue传递到templateFunctionTwo时,Fn被推导为Fn&(由于转发引用)。

线下
&templateFunctionOne< Fn >,

手段
&templateFunctionOne< Fn& >,

这意味着templateFunctionOne通过引用接受其参数,
如果要在调用async时通过引用传递参数
您需要使用包装器std::refstd::cref:
   std::future< bool > tk =  std::async(
               templateFunctionOne< Fn >,
               std::ref( std::forward<Fn>(fn) ) ); // <--- ref added

现在,您的代码开始编译。

另一种方法是使用remove_reference_t<Fn>typename std::remove_reference<Fn>::typeFn删除左值引用:
  std::future< bool > tk =  std::async(
     templateFunctionOne< std::remove_reference_t<Fn> >, // <--- remove_reference_t added
     std::forward<Fn>(fn)  );
     return tk.get();

然后按值传递fn对象。这个版本比第一个版本好,因为
 templateFunctionTwo( std::bind( &printThis, std::placeholders::_1 ) )

使用ref时失败,因为ref仅需要采用Lvalues。

09-05 12:03
查看更多