内容主要搬运于知乎auto使用过程中的坑
一、用法
在函数返回值 / range-for 等情况中使用 auto 时,有 5 种用法
auto
:拷贝auto&
:左值引用,只能接左值(和常量右值)auto&&
:万能引用,能接左值和右值const auto&
:const 万能引用,能接左值和右值const auto&&
:常量右值引用,只能接右值
很多人直接就写 auto&&,但尽量分场景使用
auto
:用于你想修改右值的情形auto&
:用于你想修改左值的情形auto&&
:用于泛型编程中的转发const auto&
:用于只读const auto&&
:基本没用,基本可被 const auto& 替代(比 const auto&
多一个语义:一定得是右值。然而这没什么用,因为你都不对其进行修改,是左还是右没什么影响)
二、实例
vector<ElementType> arr;
for(auto ele : arr) {
// auto, 意味着下边的代码需要修改并使用 ele,但并不修改 arr中的变量
// ...
}
for(auto& ele : arr) {
// auto&,意味着下边的代码需要修改 arr 中的 ele
// ...
}
for(const auto& ele : arr) {
// const auto&,意味着下边的代码无需改动 ele
}
auto&& result = foo(); // auto&& 意味着后边要转发
bar(std::forward<decltype(result)>(result));
也就是说,4 种情形后边代表的语义是不一样的
比如明明不需要修改值的场合却用了 auto&&
赋予了修改权限
所以一般情况下,我默认选择的是 const auto&
,如果发现需要修改,再选择 auto&
或auto
(函数返回值如果是右值,是不用标记为 &&
的,并且赋值处也不需要写上 &&
,编译器会把这个部分优化掉)
在泛型编程的转发情况中,选择 auto&&
(非转发情况就跟上边的一样)
auto&&
还有一种特殊情况,就是需要区分是左值引用还是右值引用的情形(这属于超级高级的优化了)
auto&& result = foo();
if constexpr (std::is_lvalue_reference_v<decltype(result)>)
// 左值引用情形
else // std::is_rvalue_reference_v<decltype(result)>
// 右值引用情形