c++ - 为什么编译器提示 std::thread 参数在转换为右值后必须是可调用的?

标签 c++ shared-ptr

如果线程函数声明更改为 void thr(std::shared_ptr<Base>& p),为什么编译器会报错.编译错误:

gcc-10.1.0/include/c++/10.1.0/thread: In instantiation of 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(std::shared_ptr&); _Args = {std::shared_ptr&}; = void]': gcc-10.1.0/include/c++/10.1.0/thread:136:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues

136 | typename decay<_Args>::type...>::value,



有人可以一步一步地解释我。

对于这个问题的任何提示,我将不胜感激。
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>

struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // Note: non-virtual destructor is OK here
    ~Base() { std::cout << "  Base::~Base()\n"; }
};

struct Derived: public Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }
};

void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // thread-safe, even though the
                                  // shared use_count is incremented
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}

int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();

    std::cout << "Created a shared Derived (as a pointer to Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    p.reset(); // release ownership from main
    std::cout << "Shared ownership between 3 threads and released\n"
              << "ownership from main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.join(); t2.join(); t3.join();

    std::cout << "after joining the threads\n" <<
     "  p.get() = " << p.get() << ", p.use_count() " <<p.use_count() << std::endl;
    std::cout << "All threads completed, the last one deleted Derived\n";
}

输出:
Base::Base()
  Derived::Derived()
Created a shared Derived (as a pointer to Base)
  p.get() = 0x57be80, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
  p.get() = 0, p.use_count() = 0
local pointer in a thread:
  lp.get() = 0x57be80, lp.use_count() = 4  
local pointer in a thread:
  lp.get() = 0x57be80, lp.use_count() = 3
local pointer in a thread:
  lp.get() = 0x57be80, lp.use_count() = 2
  Derived::~Derived()
  Base::~Base()
after joining the threads
  p.get() = 0, p.use_count() 0
All threads completed, the last one deleted Derived

最佳答案

传递给 std::thread 的参数构造函数将被复制,然后作为右值转发给在新线程中运行的函数。因此,当您创建 std::thread像这样:

std::thread t1(thr, p)

论据 p将被复制,然后作为右值转发。如果函数thr需要一个左值引用,那么它不能用右值调用。

静态断言告诉您不能调用 thr(shared_ptr<Base>&)带有右值 shared_ptr<Base> . (在我添加静态断言之前,您只是从 std::thread 的内部深处得到了一个可怕的模板实例化错误,现在的想法是它会告诉您英文有什么问题)。

将引用传递给函数的解决方案是使用 std::ref创建 reference_wrapper 的函数目的:
std::thread t1(thr, std::ref(p))

这将创建一个 std::reference_wrapper<std::shared_ptr<Base>>被复制并转发到 thr作为右值,然后该右值可以转换为shared_ptr<Base>&初始化thr的参数功能。

这在 https://en.cppreference.com/w/cpp/thread/thread/thread#Notes 上也有清楚的解释。

关于c++ - 为什么编译器提示 std::thread 参数在转换为右值后必须是可调用的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61985888/

相关文章:

c++ - 我的函数返回一个错误的值 C++

c++ - 我可以用 Boost interval_map 做到这一点吗?

c++ - 将带有 lambda 的 std::shared_ptr 插入 vector 中

c++ - 如何在装饰器模式实现中正确使用 shared_ptr?

c++ - 如何在 dll 中创建一个 shared_ptr 并通过工厂函数导出它?

c++ - '转换': 'class' OpenGL 3D type redefinition

c++ - 帮助模板特化

C++ "' DOMDocument' : redefinition"Error with Xercesc

c++ - 通过 shared_ptr 的成本

c++ - 如何故意删除 boost::shared_ptr?