一个右值引用传递参数,编译失败了,为啥
一个右值引用传递参数,编译失败了,为什么?
但是下面这样就有问题了:
gcc提示cannot bind 'M' lvalue to 'M&&'. VC也编译不了
难以理解这个错误。
前面能编译过的程序,看起来是把一个M()构造产生的右值, 给了一个M&&右值引用
在gcc里面调试,显示rref的类型是const <unknown type>
vc里面调试,显示rref是一个M&&
那么
1. rref如果是一个右值引用的话,传递给f就没有问题。
但是因为M&& rref=M()主句话当中rref出现在等号左边,并且有名字,所以我又认为它是左值。
2. 因此,如果rref是左值,那我可以理解f(rref)不能编译。可是M&& rref=M(); 这样写本身没有报错? 可以用&&来声明一个左值?
所以问题是:
rref到底算是什么类型? 如果算右值, 为何不能传给f? 如果算左值, 为什么能用M&& rref=M()这样写?
(这里没有模板,没有类型推导)
------解决思路----------------------
M&& rref=M(); //这里的M()是右值。
M&& rref=M(); //这里的M()也是右值,rref也是右值引用类型的变量,能够持有右值,但rref作为一个具名变量,这个变量就是左值。
f(rref); //所以,将一个具名变量rref(即左值)传给f(),会编译报错。
------解决思路----------------------
有名的右值引用,其实是左值引用 。
即 M && rvRef =M(); 和定义 M& reRef =M() ;
是一样的,所以不能传递给参数为右值引用的函数。
右值引用类型,不同于其它类型,
它是专门为某些功能定义的特殊类型。
一般只用作函数参数。
也就是说,有名右值引用,作为表达式,他就是个左值引用。
这就像数组定义差不多哦,作为表达式,
数组名,优先解析为指针,除了某些特殊情况
如作为 1)函数参数,形参为数组引用 2)数组取地址,3)
数组取大小;这三种情况下,数组名不做指针解析。
右值引用也类似,
有名的右值引用,在表达式中是个左值引用。就这样。
在函数形参中,是个右值引用。实参中是左值引用
------解决思路----------------------
可以这样:
f((M&&)rref);
带模板参数的最好使用:
f(std::move(rref));
------解决思路----------------------
先补充下左值和右值:临时对象(无名)和将亡值为右值,其他为左值。
M&& ref2 是个右值类型的引用,能够持有右值,但ref2具名变量本身是个左值。
------解决思路----------------------
你刚开始可能一开始觉得有些奇怪,不出几天就习惯了。
M&& ref2 = ***; 第一此声明的时候这样,以后再别的地方使用ref2的时候,它就是作值。
------解决思路----------------------
rref 是左值,加 move(rref) 变成右值就可以调用了。
------解决思路----------------------
都说了,M&& ref2,这个地方是ref2第一次被声明为右值引用,故只能绑定右值。 但后面,ref2作为实参,再传给其他函数的时候,因为有名字,符合左值的特性,就会被当作左值去看待。
class M{};
int main()
{
M&& rref=M(); //没有问题
return 0;
}
但是下面这样就有问题了:
class M{};
void f(M&&){}
int main()
{
M&& rref=M();
f(rref);
return 0;
}
gcc提示cannot bind 'M' lvalue to 'M&&'. VC也编译不了
难以理解这个错误。
前面能编译过的程序,看起来是把一个M()构造产生的右值, 给了一个M&&右值引用
在gcc里面调试,显示rref的类型是const <unknown type>
vc里面调试,显示rref是一个M&&
那么
1. rref如果是一个右值引用的话,传递给f就没有问题。
但是因为M&& rref=M()主句话当中rref出现在等号左边,并且有名字,所以我又认为它是左值。
2. 因此,如果rref是左值,那我可以理解f(rref)不能编译。可是M&& rref=M(); 这样写本身没有报错? 可以用&&来声明一个左值?
所以问题是:
rref到底算是什么类型? 如果算右值, 为何不能传给f? 如果算左值, 为什么能用M&& rref=M()这样写?
(这里没有模板,没有类型推导)
------解决思路----------------------
M&& rref=M(); //这里的M()是右值。
M&& rref=M(); //这里的M()也是右值,rref也是右值引用类型的变量,能够持有右值,但rref作为一个具名变量,这个变量就是左值。
f(rref); //所以,将一个具名变量rref(即左值)传给f(),会编译报错。
------解决思路----------------------
有名的右值引用,其实是左值引用 。
即 M && rvRef =M(); 和定义 M& reRef =M() ;
是一样的,所以不能传递给参数为右值引用的函数。
右值引用类型,不同于其它类型,
它是专门为某些功能定义的特殊类型。
一般只用作函数参数。
也就是说,有名右值引用,作为表达式,他就是个左值引用。
这就像数组定义差不多哦,作为表达式,
数组名,优先解析为指针,除了某些特殊情况
如作为 1)函数参数,形参为数组引用 2)数组取地址,3)
数组取大小;这三种情况下,数组名不做指针解析。
右值引用也类似,
有名的右值引用,在表达式中是个左值引用。就这样。
在函数形参中,是个右值引用。实参中是左值引用
------解决思路----------------------
可以这样:
f((M&&)rref);
带模板参数的最好使用:
f(std::move(rref));
------解决思路----------------------
先补充下左值和右值:临时对象(无名)和将亡值为右值,其他为左值。
M&& ref2 是个右值类型的引用,能够持有右值,但ref2具名变量本身是个左值。
------解决思路----------------------
你刚开始可能一开始觉得有些奇怪,不出几天就习惯了。
M&& ref2 = ***; 第一此声明的时候这样,以后再别的地方使用ref2的时候,它就是作值。
------解决思路----------------------
rref 是左值,加 move(rref) 变成右值就可以调用了。
------解决思路----------------------
都说了,M&& ref2,这个地方是ref2第一次被声明为右值引用,故只能绑定右值。 但后面,ref2作为实参,再传给其他函数的时候,因为有名字,符合左值的特性,就会被当作左值去看待。