void f4(const std::unique_ptr<int>& t) {
// 左值匹配该函数
printf("const std::unique_ptr<int>&\n");
}
void f4(std::unique_ptr<int>&& t) {
// 右值匹配该函数
printf("std::unique_ptr<int>&&\n");
}
void f4(const std::shared_ptr<int>& t) {
// 左值匹配该函数
printf("const std::shared_ptr<int>&\n");
}
void f4(std::shared_ptr<int>&& t) {
// 右值匹配该函数
printf("std::shared_ptr<int>&&\n");
}
template <class T>
void f3(T&& t) {
// t为模板参数,不知道传入的是左值还是右值,需要使用forward转发参数给f4
f4(std::forward<T>(t));
}
template <class T>
void f2(T&& t) {
// t为模板参数,不知道传入的是左值还是右值,捕获t的时候需要使用forward
[t1 = std::forward<T>(t)]() mutable {
// 增加mutable属性是为了让捕获的参数可修改,此时t1的类型为T
// 如果删除mutable属性,此时t1的类型为const T,使用move是无任何效果的
// 使用std::move将t1强制转换成右值传递给f3(注意:如果没有mutable属性,虽然使用了std::move,但是传递给f3的还是左值)
f3(std::move(t1));
}();
}
template <class T>
void f1(T&& t) {
// t为模板参数,不知道传入的是左值还是右值,需要使用forward转发参数给f2
f2(std::forward<T>(t));
}
int main() {
auto p = std::make_unique<int>(100);
f1(std::move(p));
assert(!p);
auto p1 = std::make_shared<int>(200);
f1(p1);
assert(p1);
f1(std::move(p1));
assert(!p1);
// 在有mutable属性的时候输出如下:
// std::unique_ptr<int>&&
// std::shared_ptr<int>&&
// std::shared_ptr<int>&&
// 在没有有mutable属性的时候输出如下:
// const std::unique_ptr<int>&
// const std::shared_ptr<int>&
// const std::shared_ptr<int>&
system("pause");
}
真正理解到了右值引用、引用折叠、变量生命周期就很容易明白什么时候使用std::move,什么时候使用std::forward。