C++11: Why rvalue reference parameter implicitly converted to lvalue

血红的双手。 提交于 2019-12-19 11:20:48

问题


Following is the simplistic code of my problem,

void overloaded (int&& x) {
  cout << "[rvalue]";
}

template <class T>
void fn (T&& x) {
  overloaded(x);
}

int main() {
    fn(0);
    return 0;
}

I got a compile error

cannot bind ‘int’ lvalue to ‘int&&

  overloaded(x);

I am confused here, x is passed as a rvalue reference into fn(). But why the overload() call in fn() complains x is a lvalue?


回答1:


One, the x argument to fn isn't an r-value reference, it's a "universal reference" (yes, this is rather confusing).

Two, the moment you give an object a name, that name is not an r-value unless explicitly "fixed", either with std::move (to make it an r-value reference, always), or with std::forward (to convert it back to its original type in the case of universal references). If you want to avoid the complaint, use std::forward to forward as the original type:

template <class T>
void fn (T&& x) {
  overloaded(std::forward<T>(x));
}



回答2:


You're not "passing x as an rvalue reference", since that statement doesn't eveb really make sense.

Here are a selection of facts about the taxonomy of types and expressions in C++:

  • There are object types and there are reference types. (There are also a few other kinds of types.)

  • Variables can be either objects or references.

  • Expressions have types, those types are (almost) always object types, never references. (That's why your statement of "passing something as a reference" doesn't make sense; you pass arguments and arguments are always expressions.) Expressions can be lvalues, xvalues or prvalues.

  • Lvalue references bind to lvalues. Rvalue references bind to rvalues. (An rvalue is either a prvalue or an xvalue.)

  • An id-expression naming a variable or parameter is an lvalue. (It's a "thing with a name", or "a location", if you will.)

Hence in the expression overloaded(x), the subexpression x is an lvalue, and it does not bind to the function that expects an rvalue (on account of its rvalue reference parameter).

The "l" and "r" in "lvalue reference" and "rvalue reference" refers to the categories of values to which the reference can bind, not to the category of the id-expression naming a variable of this reference type.

You can convert an lvalue to an rvalue by casting it to an xvalue; this is conveniently encapsulated into the type-deducing cast helper std::move.



来源:https://stackoverflow.com/questions/48999129/c11-why-rvalue-reference-parameter-implicitly-converted-to-lvalue

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