dimanche 30 juillet 2017

C++ pass variadic template argument as reference to std::thread via perfect forwarding

Consider this simple variadic template function that spawns a thread and forwards the args to the thread function. Why do I get a template substitution failure on the thread constructor here?

std::thread t;

void test3(int& a)
{
    a = 10;
}

template<class ...Args>
void test(Args&&... args)
{
   t = std::thread(test3, std::forward<Args>(args)...);
}

int main()
{
    auto timer = 2s;

    int a = 1;
    test(a);
    std::this_thread::sleep_for(timer);
    std::cout << a << std::endl;
    t.join();
}

Compiler output:

template argument deduction/substitution failed:
/opt/wandbox/gcc-head/include/c++/8.0.0/bits/invoke.h: In substitution of 
'template<class _Callable, class ... _Args> constexpr typename 
std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, 
_Args&& ...) [with _Callable = void (*)(int&); _Args = {int}]':
/opt/wandbox/gcc-head/include/c++/8.0.0/thread:233:29:   required by 
substitution of 'template<long unsigned int ..._Ind> decltype 
(std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void 
(*)(int&), int> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with 
long unsigned int ..._Ind = {0, 1}]'
/opt/wandbox/gcc-head/include/c++/8.0.0/thread:240:2:   required from 
'struct std::thread::_Invoker<std::tuple<void (*)(int&), int> >'
/opt/wandbox/gcc-head/include/c++/8.0.0/thread:127:22:   required from 
'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)
 (int&); _Args = {int&}]'
prog.cc:23:14:   required from 'void test(Args&& ...) [with Args = {int&}]'
prog.cc:43:11:   required from here
/opt/wandbox/gcc-head/include/c++/8.0.0/bits/invoke.h:89:5: error: no type 
named 'type' in 'struct std::__invoke_result<void (*)(int&), int>' 

When I wrap the forwarding of the arguments with a std::ref like this:

std::thread(test3, std::ref(std::forward<Args>(args)...));

It works. Aren't the arguments supposed to be perfectly forwarded in the first place?

Aucun commentaire:

Enregistrer un commentaire