http://en.cppreference.com/w/cpp/language/range-for
语法:
for ( range_declaration : range_expression ) loop_statement
for (一个变量名 : 可迭代范围) {
//循环语句
}
变量名的类型可以是:容器元素的类型,容器元素的引用类型,auto
{
auto && __range =range_expression;for (auto __begin =begin_expr,__end =end_expr;__begin != __end; ++__begin) {
- range_declaration
= *__begin; - loop_statement
}
}
Boost中定义了很多”范围”,很多标准库函数都使用了范围风格的实现。这一概念被C++11提了出来:
int arr[5];
vector<int> v;
for(int x: arr);
for(const int& x: arr);
for(int x: v);
for( const auto & x : arr)
https://www.zhihu.com/question/65260546/answer/229573215
基于范围的for循环中原始数组可以编译通过,但是对于用指针动态创建的数组、或者数组作为参数传递时被退化成了指针却不可以,为什么?
int a[]={1,2,3,4,5,6};
int *p=new int[6];
for (auto x:a) { //同一个作用域内,数组a的类型就是数组; 但如果作为函数参数,也是不可以的
cout<<x<<" ";
}
// for(auto x:p){
//cout<<x<<" ";
//} 编译错误
答:
简单来说, 数组和指针不是一个东西, 指针没有保存长度信息.
详细点就涉及到了C++中range based for的实现了, 实际上
for (auto x: a) { /* ... */ }
调用了 std::begin(a) 和 std::end(a) 来判断迭代的起点和终点, 也就是实际上是长这样的(假装using namespace std了)
for (auto whatever = begin(a); whatever != end(a); ++whatever) {
auto x = *whatever;
/* ... */
}
对于一般的重载了begin和end方法的对象(比如std::vector), 这两个全局函数会调用它们的这两个方法,
对于C风格数组, std::begin 和 std::end 是模板特化的, 简单来说就是特判了【特化为数组的引用】, 而对于指针类型, 没有重载, 所以会报错
error: ‘begin’ was not declared in this scope, error: ‘end’ was not declared in this scope
或者
error: invalid range expression of type 'int *'; no viable 'begin' function available
之所以没法重载指针的begin和end, 还是因为无法从指针获得长度信息.
随手打的std::begin和std::end对数组的特化
template <typename T, std::size_t N>
begin(T (&a)[N]) { return a; } //参数:数组的引用
template <typename T, std::size_t N>
end(T (&a)[N]) { return a + N; }
- #include <iostream>
- #include <map>
- int main(void)
- {
- std::map<std::string, int> mm =
- {
- { "1", 1 }, { "2", 2 }, { "3", 3 }
- };
- for(auto& val : mm)
- {
- std::cout << val.first << " -> " << val.second << std::endl;
- }
- return 0;
- }
- for 循环中 val 的类型是 std::pair。因此,对于 map 这种关联性容器而言,需要使用 val.first 或 val.second 来提取键值。
- auto 自动推导出的类型是容器中的 value_type,而不是迭代器。
浙公网安备 33010602011771号