范围for 和 万能引用
万能引用(Universal Reference)
条件:
-
T&&
中的T
需要被模板参数推导(即T
是模板类型参数或auto
)。 -
形式:
-
在 函数模板参数 中:
template <typename T> void foo(T&& arg)
-
在
auto&&
声明中:auto&& x = ...
-
特点:
-
可以绑定到 左值或右值。
-
通常用于 完美转发(
std::forward
)。
范围for
for (auto x : container) {//这里X是容器的元素// 循环体
}上面会被替换成下面
{auto&& __range = container; // 获取容器引用auto __begin = __range.begin(); // 获取起始迭代器auto __end = __range.end(); // 获取结束迭代器for (; __begin != __end; ++__begin) { // 遍历auto x = *__begin; // 解引用获取当前元素// 循环体}
}如果是 左值容器(如变量),推导为 左值引用(Container&),避免拷贝。如果是 右值容器(如临时对象),推导为 右值引用(Container&&),延长临时对象生命周期至循环结束。也就是说,范围for的条件是
1.容器必须提供 begin() 和 end() 方法,返回迭代器2.定义迭代器类,并实现:operator*(解引用)operator++(递增)operator!=(比较)如果容器是数组,那迭代器其实就是指针
1.__begin 和 __end 就是指针,因为数组名在大多数情况下会退化为首元素指针。2.指针本身支持 *(解引用)、++(移动到下一个元素)、!=(比较地址),因此完全符合迭代器的要求。X使用引用类型
for (auto& x : container) {// 循环体
}{auto&& __range = container; // 获取容器引用auto __begin = __range.begin(); // 获取起始迭代器auto __end = __range.end(); // 获取结束迭代器for (; __begin != __end; ++__begin) { // 遍历auto& x = *__begin; // 解引用获取当前元素// 循环体}
}auto默认是丢弃引用的,如果返回的容器的元素需要引用类型的话,要在for里使用auto&