12 万能引用及完美转发
万能引用
定义
万能引用(Universal Reference)是指在模板函数或auto推导中,形如T&&
的参数。当编译器通过类型推导确定T
时,T&&
可以绑定到左值或右值
1.函数模板:
1 | template <typename T> |
- 如果
arg
是左值,T
会被推导为左值引用类型(如int&
),因此T&&
会折叠成int& &
,简化为int&
- 如果
arg
是右值,T
会被推导为普通类型(如int
),因此T&&
就是int&&
2.auto:
1 | auto&& x = some_value; // x 是万能引用 |
- 如果
some_value
是左值,auto&&
会推导为左值引用类型(如int&
) - 如果
some_value
是右值,auto&&
会推导为右值引用类型(如int&&
)
在写for循环的时候,如果不确定输入的到底是左值还是右值,也可以用万能引用
- for(auto& user : users) - 引用左值:
- 当你想要修改容器中的元素,并且
users
是一个左值时,使用引用引用(auto&
)。 - 这允许你在循环中直接修改元素。
- 当你想要修改容器中的元素,并且
- for(auto user : users) - 拷贝值:
- 当你不需要修改容器中的元素,或者
users
是一个右值时,使用值语义(auto
)。 - 这会导致容器中的每个元素被拷贝到循环变量
user
中。
- 当你不需要修改容器中的元素,或者
- for(auto&& user : users) - 引用右值(==万能引用==):
- 这种形式通常用于通用编程,特别是当你不知道容器是左值还是右值时。
- 如果
users
是左值,auto&&
会被推导为auto&
,即引用左值。 - 如果
users
是右值,auto&&
会被推导为auto
,即值语义,但注意,这不会触发移动语义,因为在范围for循环中,元素不会被移动。
注意:万能引用只能用于模板函数或者auto,如果不是这种场合,则变成右值引用
1 | void func(int&& arg) { |
完美转发
定义
完美转发用于将函数参数以最优的方式传递到另一个函数,同时保持参数的值类别(左值或右值)。它确保了传递的参数不会经历不必要的复制或者不正确的值类别转换。
完美转发只能用于模板函数,并结合万能引用和
std::forward()
核心思想
当我们在某个函数中接受参数时,通常希望将这些参数转发给另一个函数,而不改变它们的值类别。如果传递的是左值,应该保持为左值;如果传递的是右值,应该保持为右值。
- 完美转发利用了万能引用和
std::forward
来实现这一点
1 |
|
关键点
- 万能引用:
T&&
在模板函数中可以绑定左值和右值,但只有通过std::forward
才能实现完美转发 std::forward<T>
:这是一个标准库模板函数,用于在完美转发中保留参数的值类别。它根据传入的类型推导决定是转发为左值还是右值- 如果传递给
std::forward<T>(arg)
的是左值,std::forward<T>(arg)
会转发为左值 - 如果传递的是右值,
std::forward<T>(arg)
会转发为右值
- 如果传递给
使用场景
1.实现转发函数: 假设我们写了一个模板函数,这个函数的作用是转发其参数到另一个函数,并保持参数的值类别(左值或右值)
1 | template <typename T> |
2.转发构造函数参数: 在类模板中,常常需要将构造函数的参数转发给其他成员函数或构造函数。为了避免不必要的复制或类型转换,通常会使用完美转发。
1 | class MyClass { |
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.