本文介绍了为什么编译器抱怨std :: thread参数在转换为右值后必须是可调用的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么编译器会抱怨将线程函数的声明更改为 void thr(std :: shared_ptr< Base>& p) .Complie错误:

Why the compiler complains if the the thread function delaration is changed to void thr(std::shared_ptr<Base>& p).Complie error:

136 |类型名称朽烂< _Args> ::类型...> ::值,

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

有人可以一步一步解释我吗.

Can someone explain me, step by step.

对于这个问题的任何提示,我将不胜感激.

I would be grateful for any hint on this question.

#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 时:

The arguments passed to the std::thread constructor will be copied and then forwarded as rvalues to the function that runs in the new thread. So when you create a std::thread like this:

std::thread t1(thr, p)

参数 p 将被复制,然后作为右值转发.如果函数 thr 需要一个左值引用,则不能使用右值来调用它.

the argument p will be copied, then forwarded as an rvalue. If the function thr expects an lvalue reference then it can't be called with an rvalue.

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

The static assertion is telling that you that you can't call thr(shared_ptr<Base>&) with an rvalue shared_ptr<Base>. (Before I added the static assertion you just got a horrible template instantiation error from deep inside the guts of std::thread, now the idea is that it tells you what's wrong in English).

将引用传递给函数的解决方案是使用 std :: ref 函数创建 reference_wrapper 对象:

The solution to passing a reference into the function is to use the std::ref function to create a reference_wrapper object:

std::thread t1(thr, std::ref(p))

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

This will create a std::reference_wrapper<std::shared_ptr<Base>> which gets copied and forwarded to thr as an rvalue, and then that rvalue can be converted to shared_ptr<Base>& to initialize the parameter of the thr function.

https://en.cppreference上也对此做了清楚的解释.com/w/cpp/thread/thread/thread#Notes

这篇关于为什么编译器抱怨std :: thread参数在转换为右值后必须是可调用的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-01 12:48