Why an Rvalue Reference is Turned into Lvalue Reference by a Universal Reference

喜夏-厌秋 提交于 2019-12-01 07:36:39

The reason is that named rvalue references are treated as lvalues.

You should use std::move inside f2 when passing t to f1 to retain rvalueness:

void f2(int&& t) {
    f1(std::move(t));
}

Here you can find a good explanation.

Calling f1(t), the argument is the expression t. Not static_cast<decltype(t)>(t) or something. Your examination of decltype(t) has nothing to do with the call of f1(t).

The expression t has type int and value category lvalue. (A rule of thumb is that if you can take the address of an expression then it is an lvalue, and you can certainly write &t). The "information" that a reference variable was originally declared as a reference is only visible via a decltype examination.

Since f1 is called with an lvalue, T is deduced to int&.

NB. You possibly want f1 to also use decltype(t) rather than T, if you ever want to see is_rvalue_reference being true in f1. For rvalue arguments, T deduces to a non-reference type, e.g. if you fix f2 by making it do f1(std::move(t)); then f1's T is int and decltype(t) in f1 is int&&.

After studying the C++11 standard, I have a vague idea on what was going on after my f1(t); in f2. I describe it here to see if I got it right:

  1. In f2, t is an lvalue of type int&& (not int, this is an important difference)
  2. the call f1(t); causes type to be deduced like this:

    2.1 when T in f1 is given an lvalue, it is deduced as a reference of that lvalue's type orint&& &

    2.2 reference collapsing causes int&& & to become int &. This is the value of T.

  3. Since the parameter of f1 is declared as T&&, the type of parameter t in f1 is int & &&. So reference collapsing occurs a second time to deduce the type of t as int &.

  4. Hence T=int & and type of parameter t is int &. i.e. parameter t is an lvalue of type int &

Any comment?

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