mardi 13 août 2019

How to properly extend std::thread to wrap spawned thread

Im trying to create a simple wrapper to be used by my application when creating threads in lew of std::thread. The only purpose of using this app thread wrapper is to ensure some code gets invoked on every spawned thread consistently. I thought this would be trivial, but the std::thread constructor and argument passing is rather complex and Im getting very cryptic build errors here.

This is a simple example of what I'm trying to do:

#include <thread>

class AppThread : public std::thread
{
    template< class Function, class... Args > 
    static void wrap( Function&& f, Args&&... args )
    {
        //Some code
        f( std::forward<Args>( args )... );
    }

public:
    template< class Function, class... Args > 
    explicit AppThread( Function&& f, Args&&... args ) : std::thread( AppThread::wrap<Function,Args...>,
                                                                      std::forward<Function>( f ), std::forward<Args>( args )... )
    {}
};

void runA() {}
void runB( int x ) {}

main()
{
    AppThread thread1 = AppThread( runA );
    //AppThread thread2 = AppThread( runB, 5 );
}

I'd like to be able to drop in AppThread wherever std:thread is being used, so extending and overriding the constructor seems like the best approach. But passing those arguments through to my wrapped method causes this cascade of errors ( gcc 7.2 )

   In file included from thread_wrap.cpp:1:0:
gcc-7.2.0/include/c++/7.2.0/thread: In instantiation of ‘struct std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >’:
gcc-7.2.0/include/c++/7.2.0/thread:127:22:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(void (&)()); _Args = {void (&)()}]’
thread_wrap.cpp:15:130:   required from ‘AppThread::AppThread(Function&&, Args&& ...) [with Function = void (&)(); Args = {}]’
thread_wrap.cpp:24:41:   required from here
gcc-7.2.0/include/c++/7.2.0/thread:240:2: error: no matching function for call to ‘std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >::_M_invoke(std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >::_Indices)’
  operator()()
  ^~~~~~~~
gcc-7.2.0/include/c++/7.2.0/thread:231:4: note: candidate: template<long unsigned int ..._Ind> decltype (std::__invoke((_S_declval<_Ind>)()...)) std::thread::_Invoker<_Tuple>::_M_invoke(std::_Index_tuple<_Ind ...>) [with long unsigned int ..._Ind = {_Ind ...}; _Tuple = std::tuple<void (*)(void (&)()), void (*)()>]
    _M_invoke(_Index_tuple<_Ind...>)
    ^~~~~~~~~
gcc-7.2.0/include/c++/7.2.0/thread:231:4: note:   template argument deduction/substitution failed:
gcc-7.2.0/include/c++/7.2.0/thread: In substitution of ‘template<long unsigned int ..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with long unsigned int ..._Ind = {0, 1}]’:
gcc-7.2.0/include/c++/7.2.0/thread:240:2:   required from ‘struct std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >’
gcc-7.2.0/include/c++/7.2.0/thread:127:22:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(void (&)()); _Args = {void (&)()}]’
thread_wrap.cpp:15:130:   required from ‘AppThread::AppThread(Function&&, Args&& ...) [with Function = void (&)(); Args = {}]’
thread_wrap.cpp:24:41:   required from here
gcc-7.2.0/include/c++/7.2.0/thread:233:29: error: no matching function for call to ‘__invoke(std::__tuple_element_t<0, std::tuple<void (*)(void (&)()), void (*)()> >, std::__tuple_element_t<1, std::tuple<void (*)(void (&)()), void (*)()> >)’
    -> decltype(std::__invoke(_S_declval<_Ind>()...))
                ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
In file included from gcc-7.2.0/include/c++/7.2.0/tuple:41:0,
                 from gcc-7.2.0/include/c++/7.2.0/bits/unique_ptr.h:37,
                 from gcc-7.2.0/include/c++/7.2.0/memory:80,
                 from gcc-7.2.0/include/c++/7.2.0/thread:39,
                 from thread_wrap.cpp:1:
gcc-7.2.0/include/c++/7.2.0/bits/invoke.h:89:5: note: candidate: template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...)
     __invoke(_Callable&& __fn, _Args&&... __args)
     ^~~~~~~~
gcc-7.2.0/include/c++/7.2.0/bits/invoke.h:89:5: note:   template argument deduction/substitution failed:
gcc-7.2.0/include/c++/7.2.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 (*)(void (&)()); _Args = {void (*)()}]’:
gcc-7.2.0/include/c++/7.2.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 (*)(void (&)()), void (*)()> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind1 ...>) [with long unsigned int ..._Ind = {0, 1}]’
gcc-7.2.0/include/c++/7.2.0/thread:240:2:   required from ‘struct std::thread::_Invoker<std::tuple<void (*)(void (&)()), void (*)()> >’
gcc-7.2.0/include/c++/7.2.0/thread:127:22:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(void (&)()); _Args = {void (&)()}]’
thread_wrap.cpp:15:130:   required from ‘AppThread::AppThread(Function&&, Args&& ...) [with Function = void (&)(); Args = {}]’
thread_wrap.cpp:24:41:   required from here
gcc-7.2.0/include/c++/7.2.0/bits/invoke.h:89:5: error: no type named ‘type’ in ‘struct std::__invoke_result<void (*)(void (&)()), void (*)()>’

Could definitely use some insight here! Thanks

Aucun commentaire:

Enregistrer un commentaire