C++ std::thread 参数在转换为右值后必须是可调用的

C++ std::thread arguments must be invocable after conversion to rvalues

我对这里发生的事情一无所知

这是一个简单的代码示例,说明了我要实现的目标:

main.cpp

#include <iostream>
#include <thread>

int main(int argc, char** argv) {

    constexpr int SIZE = 10;

    std::array<int, SIZE> arr{0};

    auto add = []<typename T>(std::array<T, SIZE>& arr) {
        for (int i = 0; i < SIZE; i++)
            arr[i] = i + 1;
    };

    std::thread t1(std::ref(add), std::ref(arr));
    t1.join();

    return 0;
}

编译命令:

g++ -std=c++20 -Wall main.cpp -pthread -o t1

错误:

In file included from /usr/include/c++/11.1.0/stop_token:35,
                 from /usr/include/c++/11.1.0/thread:40,
                 from main.cpp:2:
/usr/include/c++/11.1.0/bits/std_thread.h: In instantiation of ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = std::reference_wrapper<main(int, char**)::<lambda(std::array<T, 10>&)> >; _Args = {std::reference_wrapper<std::array<int, 10> >}; <template-parameter-1-3> = void]’:
main.cpp:15:48:   required from here
/usr/include/c++/11.1.0/bits/std_thread.h:130:72: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
  130 |                                       typename decay<_Args>::type...>::value,
      |                                                                        ^~~~~
/usr/include/c++/11.1.0/bits/std_thread.h:130:72: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
/usr/include/c++/11.1.0/bits/std_thread.h: In instantiation of ‘struct std::thread::_Invoker<std::tuple<std::reference_wrapper<main(int, char**)::<lambda(std::array<T, 10>&)> >, std::reference_wrapper<std::array<int, 10> > > >’:
/usr/include/c++/11.1.0/bits/std_thread.h:203:13:   required from ‘struct std::thread::_State_impl<std::thread::_Invoker<std::tuple<std::reference_wrapper<main(int, char**)::<lambda(std::array<T, 10>&)> >, std::reference_wrapper<std::array<int, 10> > > > >’
/usr/include/c++/11.1.0/bits/std_thread.h:143:29:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = std::reference_wrapper<main(int, char**)::<lambda(std::array<T, 10>&)> >; _Args = {std::reference_wrapper<std::array<int, 10> >}; <template-parameter-1-3> = void]’
main.cpp:15:48:   required from here
/usr/include/c++/11.1.0/bits/std_thread.h:252:11: error: no type named ‘type’ in ‘struct std::thread::_Invoker<std::tuple<std::reference_wrapper<main(int, char**)::<lambda(std::array<T, 10>&)> >, std::reference_wrapper<std::array<int, 10> > > >::__result<std::tuple<std::reference_wrapper<main(int, char**)::<lambda(std::array<T, 10>&)> >, std::reference_wrapper<std::array<int, 10> > > >’
  252 |           _M_invoke(_Index_tuple<_Ind...>)
      |           ^~~~~~~~~
/usr/include/c++/11.1.0/bits/std_thread.h:256:9: error: no type named ‘type’ in ‘struct std::thread::_Invoker<std::tuple<std::reference_wrapper<main(int, char**)::<lambda(std::array<T, 10>&)> >, std::reference_wrapper<std::array<int, 10> > > >::__result<std::tuple<std::reference_wrapper<main(int, char**)::<lambda(std::array<T, 10>&)> >, std::reference_wrapper<std::array<int, 10> > > >’
  256 |         operator()()
      |         ^~~~~~~~

注:

如果我将 lambda 更改为:

auto add = []<typename T>(std::array<T, SIZE> arr)

并像这样调用线程:

std::thread t1(std::ref(add), arr);

它编译了,但显然数组没有改变,因为它是一个副本而不是引用

std::reference_wrapper不是std::array,所以无法推导出T

add(std::ref(arr)); 也不编译。

你可能会用到

std::thread t1([&](auto arg){ add(arg.get()); }, std::ref(arr));

Demo