简体   繁体   English

C ++ 11:为什么将右值引用参数隐式转换为左值

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

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&& ' 无法将' int '左值绑定到' int&& '

  overloaded(x); 

I am confused here, x is passed as a rvalue reference into fn() . 我在这里感到困惑, x作为右值引用传递到fn() But why the overload() call in fn() complains x is a lvalue? 但是,为什么在fn()overload()调用抱怨x是左值?

You're not "passing x as an rvalue reference", since that statement doesn't eveb really make sense. 您不会“将x作为右值引用传递”,因为该语句实际上并没有意义。

Here are a selection of facts about the taxonomy of types and expressions in C++: 以下是有关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.) (右值可以是prvalue或xvalue。)

  • An id-expression naming a variable or parameter is an lvalue. 命名变量或参数的id表达式是左值。 (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). 因此,在表达式overloaded(x) ,子表达式x是一个左值,并且不绑定到期望右值的函数(由于其右值引用参数)。

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. “左值引用”和“右值引用”中的“ l”和“ r”是指引用可以绑定的值的类别, 而不是命名该引用类型的变量的id表达式的类别。

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 . 可以方便地将其封装到类型推断的强制转换助手std::move

One, the x argument to fn isn't an r-value reference, it's a "universal reference" (yes, this is rather confusing ). 第一, fnx参数不是r值引用, 而是“通用引用” (是的, 这很令人困惑 )。

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). 二,给对象起一个名字,除非使用std::move (总是使其成为r值引用)或使用std::forward ,否则该名字不是r值,除非明确“固定”。 (在通用引用的情况下,将其转换回其原始类型)。 If you want to avoid the complaint, use std::forward to forward as the original type: 如果要避免投诉,请使用std::forward转发为原始类型:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM