Reputation: 89
I'm running into this template deduction/substitution problem when passing a function through. Could someone help, I'd appreciate it very much:
#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;
}
Here are the errors when compiling the code:
example.cpp: In instantiation of 'bool Region::setAllValues(D&, Fn&&) [with Fn = std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&; D = Region1Data]': example.cpp:72:39: required from 'bool Region::setRegion(D&) [with D = Region1Data]' example.cpp:106:17: required from here example.cpp:59:63: error: no matching function for call to 'async(std::launch, , Region, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&)' std::forward< Fn >( fn ) ) ); ^ example.cpp:59:63: note: candidates are: In file included from example.cpp:3:0: /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:75:5: note: template std::future::type> std::async(std::launch, _Fn&&, _Args&& ...) async(launch __policy, _Fn&& __fn, _Args&&... __args) ^ /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:75:5: note: template argument deduction/substitution failed: /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future: In substitution of 'template std::future::type> std::async(std::launch, _Fn&&, _Args&& ...) [with _Fn = bool (Region::)(int, Region1Data&, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&&); _Args = {Region, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&}]': example.cpp:59:63: required from 'bool Region::setAllValues(D&, Fn&&) [with Fn = std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&; D = Region1Data]' example.cpp:72:39: required from 'bool Region::setRegion(D&) [with D = Region1Data]' example.cpp:106:17: required from here /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:75:5: error: no type named 'type' in 'class std::result_of::(Region, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&))(int, Region1Data&, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&&)>' example.cpp: In instantiation of 'bool Region::setAllValues(D&, Fn&&) [with Fn = std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&; D = Region1Data]': example.cpp:72:39: required from 'bool Region::setRegion(D&) [with D = Region1Data]' example.cpp:106:17: required from here /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:95:5: note: template std::future::type> std::async(_Fn&&, _Args&& ...) async(_Fn&& __fn, _Args&&... __args) ^ /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:95:5: note: template argument deduction/substitution failed: /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future: In substitution of 'template std::future::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {bool (Region::)(int, Region1Data&, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&&), Region, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&}]': example.cpp:59:63: required from 'bool Region::setAllValues(D&, Fn&&) [with Fn = std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&; D = Region1Data]' example.cpp:72:39: required from 'bool Region::setRegion(D&) [with D = Region1Data]' example.cpp:106:17: required from here /opt/devl/optimize/gcc-4.9.3/include/c++/4.9.3/future:95:5: error: no type named 'type' in 'class std::result_of::)(int, Region1Data&, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&&), Region, int&, std::reference_wrapper, std::_Bind::*)(int, Region1Data&)>(Region, std::_Placeholder<1>, std::_Placeholder<2>)>&)>'
Upvotes: 1
Views: 474
Reputation: 20949
setAllValues
is called with Lvalue:
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
}
Due to forwarding reference rules Fn
is deduced to be Fn&
- as Lvalue reference.
template< class D >
template< class Fn > bool Region< D >::setAllValues( D& dataPack,
Fn&& fn ) // Fn is Fn&
In below
&Region::setRegionValue< std::remove_reference_t< Fn > >,
^^^ you put explicitly type in template argument list
referenceness of Fn
is removed. Because you specify explicitly parameter of setRegionValue
to be Fn
, type of its third parameter is Fn&&
- Rvalue ref.
Forwarding Lvalue by forward<Fn>(fn)
to Rvalue doesn't match, and that is why the code failed.
To handle Fn
as Lvalue you could write:
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;
}
in case of &Region::setRegionValue< Fn >
, setRegionValue
takes its third parameter as Fn&
.
Because async
takes all its parameters by value (as decayed) you have to use std::ref
to wrap Lvalue into std::reference_wrapper
.
Above code doesn't handle case when passing Rvalue into setAllValues
.
If you wrote:
return setAllValues( dataPack, std::bind( &Region::computeValue, this,
std::placeholders::_1, std::placeholders::_2 ) );
definition of setAllValues
should be:
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;
}
in which fn
as temporary is just forwarded.
It is hard to accommodate std::ref
(which is required by std::async
) with std::forward
in one call, you could make two overloads:
template < class Fn > bool setAllValues( D&, Fn&& ); // uses std::forward
template < class Fn > bool setAllValues( D&, Fn& ); // uses std::ref
to handle both cases.
Upvotes: 1