【问题标题】:template argument deduction/substitution failed in multithreading模板参数推导/替换在多线程中失败
【发布时间】:2020-02-07 15:29:00
【问题描述】:

我在传递一个函数时遇到了这个模板推导/替换问题。有人可以帮忙吗,非常感谢:

#include <iostream>
#include <vector>
#include <future>


template< class D > class Region
{

public:

  virtual bool                   setRegion( D& );

protected:


  int                            computeValue( int input, D& dataPack );
  template < class Fn > bool     setRegionValue( const int, D&, Fn&& );
  template < class Fn > bool     setAllValues( D&, Fn&& );

protected:

  std::vector< int >                  m_regionValues;
  std::vector< std::future< bool > >  m_futures;
};



template< class D > int Region< D >::computeValue( const int input,
                                                   D& dataPack )
{
  return input * dataPack.getData();
}


template< class D > 
template < class Fn > bool Region< D >::setRegionValue( const int input,
                                                        D& dataPack,
                                                        Fn&& function )
{
  int output = function( input, dataPack, output );
  m_regionValues.push_back( output * 2 );
  //check..
  return true;
}
  

template< class D > 
template< class Fn > bool Region< D >::setAllValues( D& dataPack,
                                                     Fn&& fn )
{
  for ( int indx = 0; indx < 10; ++indx )
  {
    int input = indx * 5;
    m_futures.push_back( std::async( std::launch::async,
                                     &Region::setRegionValue< std::remove_reference_t< Fn > >,
                                     this, input, std::ref( dataPack ),
                                     std::forward< Fn >( fn ) ) );
  }

  //check thread status..
  return true;
}


template< class D > bool Region< D >::setRegion( D& dataPack )
{
  auto func = std::bind( &Region::computeValue, this,
                         std::placeholders::_1, std::placeholders::_2 );
  
  return setAllValues( dataPack, func );
}


struct Region1Data
{
  int        m_regionData;
  int        getData() const;
};


int Region1Data::getData() const
{
  return m_regionData;
}
  

class Region1: public Region< Region1Data >
{
public:

  bool                         setRegion( Region1Data& );
  void                         outputValue();
};


void Region1::outputValue()
{
  //..
}


bool Region1::setRegion( Region1Data& dataPack )
{
  if ( !Region::setRegion( dataPack ) )
  {
    return false;
  }

  outputValue();
  return true;
}


int main()
{
  Region1 thisRegion;
  Region1Data dataPack;
  dataPack.m_regionData = 10;
  
  thisRegion.setRegion( dataPack );
  return 0;
}

以下是编译代码时的错误:

example.cpp: 在 'bool Region::setAllValues(D&, Fn&&) [with Fn = std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder)>&; D = Region1Data]': example.cpp:72:39: 'bool Region::setRegion(D&) [with D = Region1Data]' 需要 example.cpp:106:17: 从这里需要 example.cpp:59:63: error: no matching function for call to 'async(std::launch, , Region, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data& )>(区域, std::_Placeholder, std::_Placeholder)>&)' std::forward( fn ) ) ); ^ example.cpp:59:63: 注意:候选人是: 在 example.cpp:3:0 包含的文件中: /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:75:5: 注意:模板 std::future::type> std::async(std::launch, _Fn&&, _Args&& ...) 异步(启动 __policy,_Fn&& __fn,_Args&&... __args) ^ /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:75:5:注意:模板参数推导/替换失败: /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:代替'模板 std::future::type> std::async(std::launch, _Fn&&, _Args&& 。 ..) [with _Fn = bool (Region::)(int, Region1Data&, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder)>&&); _Args = {Region, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder)>&}]': example.cpp:59:63: 'bool Region::setAllValues(D&, Fn&&) [with Fn = std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder , std::_Placeholder)>&; D = Region1Data]' example.cpp:72:39: 'bool Region::setRegion(D&) [with D = Region1Data]' 需要 example.cpp:106:17: 从这里需要 /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:75:5: 错误:'class std::result_of::(Region, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder)>&) )(int, Region1Data&, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder)>&&)>' example.cpp: 在 'bool Region::setAllValues(D&, Fn&&) [with Fn = std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder)>&; D = Region1Data]': example.cpp:72:39: 'bool Region::setRegion(D&) [with D = Region1Data]' 需要 example.cpp:106:17: 从这里需要 /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:95:5: 注意:模板 std::future::type> std::async(_Fn&&, _Args&& ...) 异步(_Fn&& __fn,_Args&&... __args) ^ /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:95:5:注意:模板参数推导/替换失败: /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:代替'template std::future::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {bool (Region::)(int, Region1Data&, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder )>&&), 区域, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std ::_Placeholder)>&}]': example.cpp:59:63: 'bool Region::setAllValues(D&, Fn&&) [with Fn = std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder , std::_Placeholder)>&; D = Region1Data]' example.cpp:72:39: 'bool Region::setRegion(D&) [with D = Region1Data]' 需要 example.cpp:106:17: 从这里需要 /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:95:5:错误:'class std::result_of:: 中没有名为“type”的类型)(int , Region1Data&, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder)>&&), Region, int& , std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder, std::_Placeholder)>&)>'

【问题讨论】:

    标签: multithreading templates


    【解决方案1】:

    setAllValues 用左值调用:

    template< class D > bool Region< D >::setRegion( D& dataPack ) {
      auto func = std::bind( &Region::computeValue, this,
                             std::placeholders::_1, std::placeholders::_2 );
    
      return setAllValues( dataPack, func );         // func as named object is Lvalue
    }
    

    由于转发引用规则,Fn 被推断为 Fn&amp; - 作为左值引用。

    template< class D > 
    template< class Fn > bool Region< D >::setAllValues( D& dataPack,
                                                         Fn&& fn )          // Fn is Fn& 
    

    在下面

    &Region::setRegionValue< std::remove_reference_t< Fn > >,
                            ^^^ you put explicitly type in template argument list 
    

    Fn 的引用被删除。因为您将setRegionValue 的显式参数指定为Fn,所以其第三个参数的类型为Fn&amp;&amp; - Rvalue ref。
    forward&lt;Fn&gt;(fn) 转发左值到右值不匹配,这就是代码失败的原因。

    要将Fn 处理为左值,您可以这样写:

    template< class D > 
    template< class Fn > bool Region< D >::setAllValues( D& dataPack,
                                                         Fn&& fn ) {             // Fn& &&fn
      for ( int indx = 0; indx < 10; ++indx )
      {
        int input = indx * 5;
        m_futures.push_back( std::async( std::launch::async,
                                         &Region::setRegionValue< Fn >,          // <- here is Fn&
                                         this, input, std::ref( dataPack ),
                                         std::ref( fn ) ) );                     // <-
      }
      return true;
    }
    

    如果是&amp;Region::setRegionValue&lt; Fn &gt;setRegionValue 的第三个参数为Fn&amp;。 因为async 按值获取所有参数(如衰减),您必须使用std::ref 将左值包装成std::reference_wrapper

    Working version 1


    将右值传递给setAllValues 时,上述代码不处理大小写。

    如果你写了:

    return setAllValues( dataPack, std::bind( &Region::computeValue, this,
                             std::placeholders::_1, std::placeholders::_2 ) );
    

    setAllValues 的定义应该是:

    template< class D > 
    template< class Fn > bool Region< D >::setAllValues( D& dataPack,
                                                         Fn&& fn ) {
      for ( int indx = 0; indx < 10; ++indx )
      {
        int input = indx * 5;
        m_futures.push_back( std::async( std::launch::async,
                                         &Region::setRegionValue< Fn >,
                                         this, input, std::ref( dataPack ),
                                         std::forward<Fn>( fn ) ) );
      }
      return true;
    }
    

    其中fn 作为临时被转发。

    Working version 2


    很难在一次调用中容纳std::refstd::async 需要)和std::forward,您可以进行两次重载:

    template < class Fn > bool     setAllValues( D&, Fn&& );   // uses std::forward
    template < class Fn > bool     setAllValues( D&, Fn& );    // uses std::ref
    

    处理这两种情况。

    【讨论】:

    • 非常感谢@rafix07,这解决了问题!非常感谢!!!
    猜你喜欢
    • 2018-04-28
    • 2014-09-22
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 1970-01-01
    • 2017-01-27
    • 2014-04-03
    • 2021-01-24
    相关资源
    最近更新 更多