左值是绑定到存储器的确定区域的值,而右值是表达式值,其存在是临时的,并且不一定是指存储器的确定区域.只要在预期rvalue的位置使用左值,编译器就会执行左值到右值的转换,然后继续进行求值.
http://www.eetimes.com/discussion/programming-pointers/4023341/Lvalues-and-Rvalues
每当我们构造一个临时(匿名)类对象或从函数返回一个临时类对象时,虽然该对象是临时的,但它是可寻址的.但是,对象仍然是有效的右值.这意味着当编译器期望使用左值时,对象是a)可寻址的右值或b)从左值隐式转换为右值.
例如:
class A
{
public:
int x;
A(int a) { x = a; std::cout << "int conversion ctor\n"; }
A(A&) { std::cout << "lvalue copy ctor\n"; }
A(A&&) { std::cout << "rvalue copy ctor\n"; }
};
A ret_a(A a)
{
return a;
}
int main(void)
{
&A(5); // A(5) is an addressable object
A&& rvalue = A(5); // A(5) is also an rvalue
}
Run Code Online (Sandbox Code Playgroud)
我们还知道函数返回的临时对象(在下面的例子中a)是lvalues作为这个代码段:
int main(void)
{
ret_a(A(5));
}
Run Code Online (Sandbox Code Playgroud)
产生以下输出:
int conversion …
显然,不允许在ref-qualifiers上重载 - 如果删除&或者&&(只是标记,而不是它们的函数),这段代码将无法编译:
#include <iostream>
struct S {
void f() & { std::cout << "Lvalue" << std::endl; }
void f() && { std::cout << "Rvalue" << std::endl; }
};
int main()
{
S s;
s.f(); // prints "Lvalue"
S().f(); // prints "Rvalue"
}
Run Code Online (Sandbox Code Playgroud)
换句话说,如果您有两个具有相同名称和类型的函数,则必须定义两者,如果您定义其中任何一个.我认为这是故意的,但是原因是什么?例如,为什么不允许调用&&rvalues 的版本(如果已定义),以及f()以下变体中的其他所有内容的"primary" (反之亦然 - 尽管这会让人感到困惑):
struct S {
void f() { std::cout << "Lvalue" << std::endl; }
void f() && { std::cout << "Rvalue" …Run Code Online (Sandbox Code Playgroud) 鉴于以下参考折叠规则
T& & - > T&T&& & - > T&T& && - > T&T&& && - > T&&第三和第四条规则意味着T(ref qualifer) &&身份转变,即T&停留在T&并T&&保持在T&&.为什么我们有两个重载std::forward?以下定义无法满足所有目的吗?
template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
T&& forward(const typename std::remove_reference<T>::type& val) {
return static_cast<T&&>(const_cast<T&&>(val));
}
Run Code Online (Sandbox Code Playgroud)
这里服务的唯一目的const std::remove_reference<T>&是不复制.并且enable_if有助于确保仅在非const值上调用该函数.我不完全确定是否const_cast需要它,因为它不是引用本身的const.
由于forward总是使用显式模板参数调用,因此我们需要考虑两种情况:
forward<Type&>(val)这里Tin 的类型forward将是T&,因此返回类型将是身份转换T&forward<Type&&>(val)这里Tin 的类型forward将是T&& …在广泛阅读ISO/IEC 14882,编程语言 - C++后,我仍然不确定为什么const需要使用单个参数构造函数隐式转换为用户定义的类型,如下所示
#include <iostream>
class X {
public:
X( int value ) {
printf("constructor initialized with %i",value);
}
}
void implicit_conversion_func( const X& value ) {
//produces "constructor initialized with 99"
}
int main (int argc, char * const argv[]) {
implicit_conversion_func(99);
}
Run Code Online (Sandbox Code Playgroud)
从第4节第3行开始
当且仅当声明T t = e时,表达式e可以隐式转换为类型T. 对于一些发明的临时变量t(8.5),其形式良好.某些语言结构要求将表达式转换为布尔值.在这样的上下文中出现的表达式e被称为在上下文中转换为bool并且当且仅当声明bool t(e)时才是格式良好的; 对于一些发明的临时变量t(8.5),其形式良好.隐式转换的效果与执行声明和初始化相同,然后使用临时变量作为转换的结果.如果T是左值引用类型(8.3.2),则结果是左值,否则为右值.当且仅当初始化将其用作左值时,表达式e用作左值.
接下来,我在8.5行6中找到了与用户定义类型相关的初始化器部分
如果程序要求对const限定类型T的对象进行默认初始化,则T应为具有用户提供的默认构造函数的类类型.
最后,我以12.3第2行结束了有关用户定义的转换的信息
用户定义的转换仅在明确无误的情况下应用(10.2,12.3.2).
不用说,10.2和12.3.2没有回答我的问题.
const隐含转换的影响吗?const12.3第2行使转换"明确"?const以某种方式影响第4节中谈到的左值与右值?我们不能写,int& ref = 40因为我们需要lvalue在右侧.但我们可以写const int& ref = 40.为什么这可能?rvalue而是40lvalue
我知道这是一个例外,但为什么呢?
从C++ 11开始,std::shuffle()对随机位生成器进行右值引用:
template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG&& g);
Run Code Online (Sandbox Code Playgroud)
所以我可以这么称呼它:
std::vector<int> v = {...};
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
Run Code Online (Sandbox Code Playgroud)
这揭示了我对C++的理解错误,我今天早上通过阅读无法满足:在这里使用右值引用可以获得什么?换句话说,为什么不这样做
template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG& g);
Run Code Online (Sandbox Code Playgroud) 例子:
typedef enum Color
{
RED,
GREEN,
BLUE
} Color;
void func(unsigned int& num)
{
num++;
}
int main()
{
Color clr = RED;
func(clr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译时出现以下错误:
<source>: In function 'int main()':
<source>:16:9: error: cannot bind non-const lvalue reference of type 'unsigned int&' to an rvalue of type 'unsigned int'
func(clr);
^~~
Run Code Online (Sandbox Code Playgroud)
我认为clr我传递给的变量 ( )func(unsigned int&)是一个左值。我可以获得的地址clr并可以为其分配另一个值。当我尝试将它传递给 时,为什么它会变成右值func(unsigned int&)?
我写这个代码:
#include <iostream>
using namespace std;
class Foo
{
public:
int a = 0;
Foo()
{
cout << "ctor: " << this << endl;
}
~Foo() {
cout << "dtor: " << this << endl;
}
};
Foo f()
{
Foo foo;
cout << "f " << &foo << endl;
return foo;
}
void ff(Foo &&ffoo)
{
cout << "ff " << &ffoo << endl;
}
int main()
{
ff(f());
std::cout << "Hello World!\n";
}
Run Code Online (Sandbox Code Playgroud)
输出看起来不错:
ctor: 0x7ffeda89bd7c
f 0x7ffeda89bd7c …Run Code Online (Sandbox Code Playgroud) 请问,有人可以用简单的英语解释什么是"将移动语义扩展到*这个"?我指的是这个提议.所有我们正在寻找的是什么,为什么我们需要它.请注意,我确实理解rvalue引用通常是什么,构建了移动语义.我无法理解这样的扩展为rvalue引用添加了什么!
假设我有一个函数的两个重载f.f(T&&)和f(T&).然后在身体g:
g(T&& t) { f(t);}过载f(T&)将调用因为t被认为是左值.
这对我来说非常令人惊讶.带签名的函数如何f(T&&)与类型的调用不匹配T&&?让我更加惊讶的是,一个电话f(static_cast<T&&>(t))实际上会调用rvalue超载f(T&&).
使这成为可能的C++规则是什么?是T&&不是类型吗?
c++ ×10
rvalue ×10
c++11 ×5
lvalue ×3
reference ×2
const ×1
constructor ×1
overloading ×1
this ×1