这可能是显而易见的,但我认为这对我来说很难。鉴于这种:
void test(std::string&&) { }
std::string x{"test"};
test(std::move(x)); // ok
此代码使用右值引用作为参数调用test()
,以便程序按照我的预期进行编译。
现在看看这个:
void other_test(const std::string&) { }
std::string x{"test"};
other_test(std::move(x)); // ok???
在这里,我倾斜了。为什么这个版本会编译? std::move
返回一个&&类型;为什么我在使用const&
的第二种方法中没有出错?
我知道
int&& s = 5;
const int& s = 5;
是有效的,因为在这两种情况下我提供的东西都没有左值,它没有地址。 &&
和const&
相当吗?如果不是,有区别吗?
std::move
实际上并没有移动任何东西。对于T&&
的演员而言,这只是一个奇特的名字。像test
一样调用test(std::move(x));
只表明T&&
可以隐式转换为const T&
。编译器看到test
只接受const T&
所以它将从T&&
返回的std::move
转换为const T&
,这就是它的全部内容。
简单来说:
&&
可以绑定到非const rvalues(prvalues和xvalues)const &&
可以绑定到rvalues(const和非const)&
可以绑定到非const值左右const &
可以绑定到rvalues(prvalues和xvalues)和lvalues(const和非const)。又名任何事情。如果您希望函数明确允许const-Lvalue对象,但明确禁止Rvalue对象,请按如下方式编写函数签名:
void test(const std::string&) { }
void test(std::string&&) = delete;//Will now be considered when matching signatures
int main() {
std::string string = "test";
test(string);//OK
//test(std::move(string));//Compile Error!
//test("Test2");//Compile Error!
}
test(std::string&& a) { something(a) //--> not moved because it has lvalue
变量名称是左值。 a
是变量的名称,因此a
是一个左值表达式,因此它不会被移动。
目前还不清楚你的意思是“有”。 a
是一种表达方式。它是引用的名称,引用引用对象。值类别与表达式有关,而与对象无关。
test(const std::string& a)
:a是const lvalue reference,就像我有lvalue和rvalue之前一样。还有更多,在这种情况下,如果我打电话std::move(a)
其中a是const&the move的作用!
如果“工作”意味着它调用移动构造函数或赋值,那么不,它不起作用,因为没有移动构造或赋值发生。
当您调用std::move(x)
时,将返回rvalue
对基础数据的引用test
。您可以将rvalue
引用作为const
(和const only!)引用参数传递,因为rvalue
引用可以隐式转换为const
引用。从函数的角度来看,它们可以说是相同的东西(只读参数)。如果删除了参数的const限定符,则此代码将无法编译:
void other_test(std::string&) { }
std::string x{"test"};
other_test(std::move(x)); //not okay because
//the function can potentially modify the parameter.