【问题标题】:When a function takes an rvalue reference, what is the type of that variable within the function?当函数接受右值引用时,函数中该变量的类型是什么?
【发布时间】:2019-06-14 17:07:31
【问题描述】:

这是一个术语问题。如果我有这个:

#include <vector>

void g(std::vector<int>&& arg);

void f0(std::vector<int>&& v) {
    static_assert(std::is_same<decltype(v), std::vector<int>&&>::value); // Looks like v is an rvalue reference.
    static_assert(std::is_same<decltype((v)), std::vector<int>&>::value);
    static_assert(std::is_same<std::decay<decltype(v)>::type, std::vector<int>>::value);
    return g(std::move(v)); // Fine.
}

那么v 是什么类型?如果您正在谈论调用f0,您会说“f0 采用右值引用”(对吗?)但在f0 内,v 不是右值引用,否则std::move 不会不需要?正确的?但是static_assert 表明它是一个右值,对吧?

同样:

void f1(std::vector<int>&& v) {
    static_assert(std::is_same<decltype(v), std::vector<int>&&>::value);
    static_assert(std::is_same<decltype((v)), std::vector<int>&>::value);
    static_assert(std::is_same<std::decay<decltype(v)>::type, std::vector<int>>::value);
    return g(v); // Error: cannot bind rvalue reference of type 'std::vector<int>&&' to lvalue of type 'std::vector<int>'.
    // So is v just a std::vector<int>?
}

本地右值引用的行为方式相同:

void f2(std::vector<int>&& v) {
    std::vector<int>&& vv = std::move(v);
    static_assert(std::is_same<decltype(vv), decltype(v)>::value, "They are the same decltype. So being an argument isn't magic.");
    static_assert(std::is_same<decltype(vv), std::vector<int>&&>::value);
    static_assert(std::is_same<decltype((vv)), std::vector<int>&>::value);
    static_assert(std::is_same<std::decay<decltype(vv)>::type, std::vector<int>>::value);
    return g(vv); // Error: cannot bind rvalue reference of type 'std::vector<int>&&' to lvalue of type 'std::vector<int>'
}

描述v 类型的正确术语是什么?说f0 采用右值引用是否正确?如果v 是右值引用,那么用什么术语说右值引用不能用于调用采用右值引用的函数?

【问题讨论】:

  • 基本上,命名的右值引用(类型)是左值(值类别)。

标签: c++ rvalue-reference lvalue-to-rvalue


【解决方案1】:

名为v 的变量的声明类型std::vector&lt;int&gt;&amp;&amp;。这种类型读作“rvalue reference to std::vector”。

名称v 可以出现在表达式中。表达式永远不会有引用类型[expr.type]/1。但是表达式有一个value category。当名称v 出现在v[0] 中的表达式中时,子表达式v 的类型为std::vector&lt;int&gt;,其值类别为lvalue。几乎所有id-expression 都是这种情况(只是名称的表达式)。

decltype(v) 给出变量v 的声明类型。

decltype(expression) 给出:

  • 如果expression 是左值,则为expression 类型的左值引用,
  • 如果expression 是xvalue,则为expression 类型的右值引用,
  • expression 的类型,如果 expression 是纯右值。

更多详情请见[dcl.dcl]/1

【讨论】:

    【解决方案2】:

    您将类型与值类别混淆了,在您的辩护中,这非常容易做到。

    是的,该函数采用“rvalue reference to std::vector&lt;int&gt;”类型的参数。该引用可以在调用点从std::vector&lt;int&gt; 类型的右值表达式初始化。

    函数内部表达式v的类型,当你开始尝试使用它时,不是std::vector&lt;int&gt;&amp;&amp;; “衰变”的参考类型。这只是参考工作机制的一部分。 (decltype 在这方面有点奇怪。)出于所有意图和目的,您最终会得到一个 std::vector&lt;int&gt; 类型的 lvalue 表达式。无论如何,在这一点上,类型有点无关紧要。关键是名称v 是一个左值,要再次将其变为右值,您需要std::move

    但是 static_assert 表明它是一个右值,对吧?

    不。 “右值引用”描述了各种类型。 “右值”是一个值类别。您可能想知道他们为什么选择如此令人困惑的术语。我也是。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 2021-05-02
      • 2020-09-20
      • 1970-01-01
      • 2017-12-03
      • 1970-01-01
      • 2020-09-12
      相关资源
      最近更新 更多