C++ multithreading and passing templated arguments <typename T>(T arg)

Viewed 37

I have this code which is working without anny issue:

void function_exit(dispatcher& d) { /* .. */ }
// ...
std::thread th(function_exit, std::ref(main_disp));
th.detach();

now I tried create another class which hold std::thread which produce errors on compilation

thread_control mtc;
mtc.create<dispatcher&>(function_exit, main_disp);

here is create function: (please read a comented text for describing a problem)

template<typename Arg>
inline bool thread_control::create(void(*function)(Arg), Arg value)
{
    bool ok = false;
    if (created == false)
    {
        created = true;
        if (typeid(Arg).hash_code() == typeid(void).hash_code())
        {
            // this produce thread(50,5): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&) noexcept(<expr>)'
            // type_traits(1583): message : see declaration of 'std::invoke'
            // thread(50,5): message : With the following template arguments:
            // thread(50,5): message : '_Callable=void (__cdecl *)(Arg)'
            m_thread = std::thread(function);
        }
        else
        {
            if (std::is_reference<Arg>::value)
            {
                // if only this function is used, program is compiled without errors and runs without problem.
                // (when i comment functions which are problematic and this function is uncomented)
                m_thread = std::thread(function, std::ref(value)); 
            }
            else
            {
                // this function produce this errors:
                // 2>...\Visual Studio 2019\VC\Tools\MSVC\14.28.29910\include\thread(65): message : see reference to function template instantiation 'unsigned int (__stdcall *std::thread::_Get_invoke<_Tuple,0,1>(std::integer_sequence<size_t,0,1>) noexcept)(void *)' being compiled
                // thread(50,5): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Ty1 &&,_Types2 &&...) noexcept(<expr>)'
                // type_traits(1589): message : see declaration of 'std::invoke'
                // thread(50,5): message : With the following template arguments:
                // thread(50,5): message : '_Callable=void (__cdecl *)(Arg)'
                // thread(50,5): message : '_Ty1=dispatcher'
                // thread(50,5): message : '_Types2={}'
                // thread(50,5): error C2780: 'unknown-type std::invoke(_Callable &&) noexcept(<expr>)': expects 1 arguments - 2 provided
                // type_traits(1583): message : see declaration of 'std::invoke'
                m_thread = std::thread(function, value);
            }
        }
        ok = true;
    }
    return ok;
}

What is wrong with my m_thread = std::thread(...); functions which throw those compilation errors? Or what I am doing wrong?

1 Answers
 if (std::is_reference<Arg>::value)

For a given Arg, this will evaluate to either true or false, of course.

However both the code that executes when this condition is true, and the code that executes when this condition is false must be valid C++.

 m_thread = std::thread(function, value);

If Arg is a reference, this is not valid C++. Even though the if condition will evaluate to true, and this will not get executed, this still must be valid C++.

There are two basic approaches that can be used here.

  1. Use if constexpr with C++17, and higher.

  2. With C++14 and earlier you will need to rewrite the whole thing to use specialization (of this entire template function, or by moving the relevant logic into template classes and specializing them).

Related