我对使用函数调用的rvalue传递感到有点困惑,请参阅下面的代码:
#include <string>
#include <iostream>
void func(std::string & s, char a) {
std::cout << "here1" << std::endl;
// ...
}
void func(std::string && s, char a) {
std::cout << "here2" << std::endl;
// ...
}
void foo(std::string && s) {
func(s, ':');
}
int main(int agrc, char *argv[])
{
std::string s = "a:b:c:d";
func(std::move(s), ':'); // print here2
char s2[8] = "a:b:c:d";
func(std::move(std::string(s2)), ':'); // print here2
foo(std::move(s2)); // print here1, why?
return 0;
}
g++-4.7 demo.cpp -std=c++11
为什么最后一种情况(使用foo
)打印here1
?
在我看来,在内部函数foo
中,s
是一个右值,因此会打印here2
。
更新:
s
中的{p> foo
是左值,但无需编写foo
的重载版本:
void foo(std::string & s) {
func(s, ':');
}
因为编译器可以了解输入参数s
是左值还是左值,但是为什么编译器不会在右值的情况下自动移动s
?
答案 0 :(得分:4)
foo
声明:
void foo(std::string && s) {
func(s, ':');
}
表示它可以接受右值引用,此信息用于方法解析。但是,在foo
范围内,参数具有名称,因此作为左值引用。基本上它已经衰减为左值参考。
如果你想在调用func
时将其视为右值引用,那么你需要将它转回到一个未命名的实例中,将其转换回右值反射。这是std::move
完成的。
答案 1 :(得分:2)
s
在函数lvalue
中为foo
,而非rvalue,因为它是本地函数参数,您的s2
将在其中移动。由于rvalues
没有名称而你的变量有名字 - 它是左值。要将其正确发送到func
,您可以使用std::forward
或std::move
。
func(std::forward<std::string>(s), ':');
或
func(std::move(s), ':');
答案 2 :(得分:0)
虽然参数作为rvalue传递给foo
,但在函数foo
内,它被视为左值,因为它有一个名称s
并且可以被该名称引用。如果您想使用“变量名称”(简单来说,左值)发送右值,请使用std::move
Scott Meyers的讲座详细解释了移动语义。如果你想知道,我推荐它,并利用移动语义
http://skillsmatter.com/podcast/home/move-semanticsperfect-forwarding-and-rvalue-references