遍历容器是种广泛的需求,在C++11之前,有些库提供了遍历容器内所有元素的封装方法,比如Boost 中的BOOST_FOREACH ,Qt 中的foreach 关键字等等,甚至C++自己也提供了一个std::for_each 算法。
C++11基于范围的for循环
std::vector coll = {1,2,3};for(inti : coll ) {std::cout<< i <
以上代码以值拷贝方式访问到容器coll中的每个元素,这里可以使用auto 来自动推导容器内元素的类型:
std::vector coll = {1,2,3};for(autoi : coll ) {std::cout<< i <
如果需要修改容器内元素的内容,则需要声明引用类型int& i 或auto& i 。所以当容器内元素类型是复杂数据类型时,为运行效率考虑计,一般推荐引用或常量引用方式访问:
std::vector coll = {"element1","element2","element3"};for(constauto& s : coll) {std::cout<< s <
std::map 是按std::pair 迭代的,所以要这样遍历std::map :
std::map mm;for(constauto& m : mm ) {std::cout<< m.first <<" < "<< m.second <<">"<
一般而言,如下一组基于范围的for循环:
for(for-range-declaration : expression )statement
等价于如下一组老式的for循环:
{auto &&__range = ( expression );for(auto__begin=begin-expr,__end=end-expr;__begin!=__end; ++__begin) {for-range-declaration = *__begin;statement}}
其中__range ,__begin 和__end 仅用于说明,__RangeT 是expression 的类型,begin-expr 和end-expr 则依据以下规则决定:
如果__RangeT 是数组类型,则begin-expr 和end-expr 分别等于__range 和__range +__bound ,相应的__bound 是数组边界。因此如此__RangeT 是不知大小的数组,或者不完整类型(有声明没定义)的数组,那么程序就不合法。
如果__RangeT 类型拥有begin() 和end() 成员函数,则begin-expr 和end-expr 分别等于__range.begin() 和__range.end() 。
否则,begin-expr 和end-expr 分别等于begin(__range) 和end(__range) ,使用参数依赖查找算法 进行查找,其实基本上就是std::begin() 和std::end() 。
__begin 和__end 具有相同的类型,在C++17中放宽了这个限制。
目前C++标准库中所有容器,std::string 和数组都能用这种基于范围的for循环遍历,如果想要让自己的数据结构也支持这种语法,需要满足以下要求:
能对此自定义数据结构类型调用begin 和end 方法,无论是成员函数或者独立函数都可以,要能返回迭代器类型。
返回的迭代器类型必须支持operator* 方法,operator!= 方法和前缀形式的operator++方法,同样无论是成员函数或独立函数都可以。
C++17的改进
C++11引入的基于范围的for循环要求begin 和end (起始值和结尾值)具有相同的类型,这对于大多数情况来说并没有什么问题,比如在遍历STL容器时,总是能返回相同类型的begin和end 。
但是有人觉得这个规范过于受限,于是C++17放开了这个限制,将原来的等价代码修改如下:
{auto &&__range =for-range-initializer;auto__begin=begin-expr;auto__end=end-expr;for( ;__begin!=__end; ++__begin) {for-range-declaration = *__begin;statement}}
与C++11中的相比,唯一的不同就是__begin 和__end 可以具有不同类型了,只要它们两个支持通过operator!= 比较即可。
加入程序员的社群。在程序员的圈子能更加积极的学习新的知识,学习编程有一个学习的氛围跟交流圈子特别重要!所以这里我推荐一下这个C语言C++直播授课群905162296,不管你是小白还是大牛欢迎入驻,大家一起交流成长。