【问题标题】:C2664 cannot convert to && valueC2664 无法转换为 && 值
【发布时间】:2020-11-03 13:59:31
【问题描述】:

编译器希望我的左值成为右值引用,但我不明白为什么。

我的问题是:

  1. 为什么“dataLen”是 const,即使它被声明为非 const 并且 lambda 被告知默认通过引用捕获?
  2. 为什么编译器会尝试转换为右值引用“unsigned __int64 &&”,即使它被声明为 tupleByteVector_content 的“unsigned long long”(无右值引用)?

我认为这是因为 lambda 捕获,但请参阅下面的简化工作流程:

void read_socket()
{
  std::vector<std::tuple<unsigned long long, std::vector<unsigned char>>> tupleByteVector_content;
  read_socket_readSome(tupleByteVector_content, [this, &tupleByteVector_content]() {
    //use tuple vector
  });
}

//catch the tuple vector by reference
void read_socket_readSome(std::vector<std::tuple<unsigned long long, const std::shared_ptr<Session>& session, std::vector<unsigned char>>> & tupleByteVector_content, std::function<void()> && continueReadFunction)
{
  //Read data length from a asio socket
  std::shared_ptr<asio::streambuf> len_buffer = std::make_shared<asio::streambuf>();
  asio::async_read(session->connection->socket->next_layer(), *len_buffer, asio::transfer_exactly(1), [&, 
  this, session, len_buffer, tupleByteVector_content, continueReadFunction](const error_code& ec, std::size_t bytes_transferred) {

    //the first value I want to save
    unsigned long long dataLen = BytesToLength(len_buffer);

    //Read data from a asio socket
    std::shared_ptr<asio::streambuf> data_buffer = std::make_shared<asio::streambuf>();
    asio::async_read(session->connection->socket->next_layer(), *data_buffer, asio::transfer_exactly(dataLen), [&, this, dataLen, data_buffer, tupleByteVector_content, session, continueReadFunction](const error_code& ec, std::size_t bytes_transferred) {

        //ERROR HERE: ----------->

        std::tuple<unsigned long long, std::vector<unsigned char>> t = 
          std::make_tuple<unsigned long long, std::vector<unsigned char>>(

          dataLen, // ERROR C2664, cant convert argument 1 from "const unsigned __int64" to "unsigned __int64 &&"

          { asio::buffers_begin(data_buffer->data()), asio::buffers_end(data_buffer->data()) });

        //ERROR HERE: <-----------
        
        tupleByteVector_content.push_back(t);

        continueReadFunction();

    });
  });
}

编辑: 我能够编译这个元组:

std::tuple<unsigned long long, std::vector<unsigned char>> t = { dataLen, { asio::buffers_begin(data_buffer->data()), asio::buffers_end(data_buffer->data()) } };

但随后对向量的 push_back 给出了错误: 错误 C2663: [...] ::push_back": 对于 2 个重载,this 指针没有转换(我自己免费翻译成英文)

【问题讨论】:

  • 你能指出你得到 hte 错误的代码行吗
  • 在代码中查找注释: //ERROR HERE 和 // ERROR C2664

标签: c++11 lambda compiler-errors lvalue-to-rvalue


【解决方案1】:
  1. dataLen 被视为 const 因为您通过值捕获它:

    [&, this, dataLen,
              ^^^
    

默认为闭包​​生成的函数调用操作符被标记为const,所以在const方法中你只能读取数据。不允许修改,除非您将mutable 添加到 lambda 的定义中。

  1. 当您使用make_tuple 时,您应该依赖模板参数推导,而不是像您所做的那样以显式方式放置类型。您的问题的简短版本:

     int i;
     std::tuple<int> t = std::make_tuple<int>(i);
    

i 是命名对象,所以它是左值。通过make_tuple&lt;int&gt;,您使make_tuple 签名看起来像:make_tuple(int&amp;&amp;)。这是编译器抱怨的地方,因为i as lvalue 不能绑定到 rvalue 引用。通过实参推导,make_tuple的参数推导为:int&amp;,此时可以绑定i

vector 上的push_back 不起作用,因为您再次按值捕获了向量。 push_back 修改对象,在调用 const 对象时是不允许的。您应该通过引用来捕获它。

【讨论】:

  • 谢谢你,在你的帮助下我可以编译代码了。但我不明白第 2 点。 i 被命名和左值,但在所有其他函数中,我可以像我一样提供左值。例如,这确实编译: std::unique_ptr l = std::make_unique(dataLen);区别在哪里?
  • 令我困惑的是:这可能是第一次,我必须在编写 C++ 代码时不那么明确才能使其工作。我希望这是脚本语言,但不是 C++。我希望至少有一种明确的方式来写这个,比如: std::tuple t = std::make_tuple NOREF(i);
  • make_tuple 对其参数使用转发引用,make_unique 也是,但是通过编写 make_unique&lt;unsigned long long&gt;,您只指定 T,而不是 Args,因此 Args 由以下规则推导出转发参考,这就是您的示例有效的原因。传递左值时,ArgsArgs&amp;,传递右值时ArgsArgs&amp;&amp;
猜你喜欢
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多