为何可向std::move传入非引用值?模板参数T的类型是什么?
为什么std::move能接收左值?模板参数T是什么?
这个问题的核心在于C++里的引用折叠规则和**转发引用(万能引用)**特性,咱们一步步拆解清楚:
1. 先搞懂std::move签名里的T&&不是普通右值引用
std::move的签名是:
template< class T > typename std::remove_reference<T>::type&& move( T&& t ) noexcept;
这里的T&&是转发引用(也叫万能引用),它的特殊之处仅在模板参数自动推导的场景生效:此时它可以匹配左值、右值、const引用等几乎所有类型,这是它能接收左值a的核心前提。如果是显式指定T的类型,那T&&就是普通的右值引用,无法绑定左值。
2. 调用std::move(a)时的模板推导过程
假设代码是:
std::string a = "a"; std::move(a);
- 传入的
a是std::string类型的左值,模板推导会自动将T推导为std::string&(左值引用类型)。 - 此时函数参数
t的类型是T&&,也就是std::string& &&。根据C++的引用折叠规则:- 左值引用和右值引用折叠后,结果是左值引用(
& && → &) - 两个右值引用折叠后,结果还是右值引用(
&& && → &&)
所以t的实际类型是std::string&,也就是左值引用,完全可以绑定到左值a上。
- 左值引用和右值引用折叠后,结果是左值引用(
3. 返回值的转换逻辑
再看返回值typename std::remove_reference<T>::type&&:
- 因为
T是std::string&,std::remove_reference<T>会剥离掉引用部分,得到原始类型std::string。 - 所以返回值的类型就是
std::string&&,也就是右值引用。这一步就把原本的左值a“转换”成了右值引用类型,让后续代码可以把它当作右值处理(比如触发移动构造/移动赋值,避免拷贝)。
4. 验证:显式指定T会怎样?
如果我们手动指定模板参数:
std::move<std::string>(a);
此时T被明确指定为std::string,T&&就是普通的std::string&&(右值引用),这时候传入左值a会直接编译报错——因为右值引用不能直接绑定左值,这也反过来验证了之前的推导逻辑:只有让模板自动推导T为左值引用,才能通过引用折叠实现接收左值的效果。
内容的提问来源于stack exchange,提问作者qweruiop
相关产品推荐
相关产品推荐

