When a function takes an rvalue reference, what is the type of that variable within the function?

烂漫一生 提交于 2019-12-11 06:05:12

问题


This is a question of terminology. If I have this:

#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.
}

then what type is v? If you are talking about calling f0, you'd say "f0 takes an rvalue reference" (right?) but within f0, v isn't an rvalue reference, or else the std::move wouldn't be required? Right? But the static_assert showed that it is an rvalue, right?

Similarly:

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>?
}

Local rvalue references act the same way:

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>'
}

What is the correct terminology to describe the type of v? Is it correct to say f0 takes an rvalue reference? If v is an rvalue reference, what's the terminology to say that an rvalue reference can't be used to call a function taking an rvalue reference?


回答1:


The declared type of the variable named v is std::vector<int>&&. This type is read "rvalue reference to std::vector".

The name v can appears in an expression. Expressions never have reference type [expr.type]/1. But expressions have a value category. When the name v appears in an expression as in v[0], the subexpression v has type std::vector<int> and its value category is lvalue. This is the case of almost all id-expression (expressions that are just a name).

decltype(v) gives the declared type of the variable v.

decltype(expression) gives :

  • a lvalue-reference to the type of expression if expression is a lvalue,
  • a rvalue-reference to the type of expression if expression is a xvalue,
  • the type of expression if expression is a prvalue.

More details are given in [dcl.dcl]/1.




回答2:


You're confusing types with value categories which, in your defence, is extraordinarily easy to do.

Yes, the function takes an argument of type "rvalue reference to std::vector<int>". This reference can be initialised from an rvalue expression of type std::vector<int>, at the callsite.

The type of the expression v inside the function, when you start to try to use it, is not std::vector<int>&&; the reference sort of "decays". That's just part of the machinery of how references work. (The decltype there is a bit of an oddity in this regard.) For all intents and purposes, you end up with an lvalue expression of type std::vector<int>. Anyway, at this point the type is sort of irrelevant; the point is that the name v is an lvalue, and to make it into an rvalue again you need std::move.

But the static_assert showed that it is an rvalue, right?

Nope. "rvalue reference" describes kinds of types. "rvalue" is a value category. You might wonder why they chose such confusing terminology. So do I.



来源:https://stackoverflow.com/questions/56602551/when-a-function-takes-an-rvalue-reference-what-is-the-type-of-that-variable-wit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!