1

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

#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呢?如果您在谈论 call f0,您会说“f0接受右值引用”(对吗?)但在 内f0v不是右值引用,否则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是右值引用,那么用什么术语说右值引用不能用于调用采用右值引用的函数?

4

2 回答 2

3

命名变量的声明类型vstd::vector<int>&&. 这种类型被读作“ rvalue reference to std::vector ”。

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

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

decltype(expression)给出:

  • expression对if类型的左值引用expression是左值,
  • expression对if类型的右值引用expression是 xvalue,
  • expressionif的类型expression是纯右值。

更多细节在[dcl.dcl]/1中给出。

于 2019-06-14T17:25:09.567 回答
2

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

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

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

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

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

于 2019-06-14T17:17:08.527 回答