不那么新的C++标准学习笔记 logo 不那么新的C++标准学习笔记

编译器支持最低版本要求:

  • GCC: 4.6
  • MSVC: 17.0
  • Clang: 3.0

提案: N2930

遍历容器是种广泛的需求,在C++11之前,有些库提供了遍历容器内所有元素的封装方法,比如Boost中的BOOST_FOREACHQt中的foreach关键字等等,甚至C++自己也提供了一个std::for_each算法。

C++11提供了基于范围的for循环:

std::vector<int> coll = { 1, 2, 3};
for( int i : coll ) {
    std::cout << i << std::endl;
}

以上代码以值拷贝方式访问到容器coll中的每个元素,这里可以使用auto来自动推导容器内元素的类型:

std::vector<int> coll = { 1, 2, 3};
for( auto i : coll ) {
    std::cout << i << std::endl;
}

如果需要修改容器内元素的内容,则需要声明引用类型int& iauto& i。所以当容器内元素类型是复杂数据类型时,为运行效率考虑计,一般推荐引用或常量引用方式访问:

std::vector<std::string> coll = { "element1", "element2", "element3"};
for (const auto& s : coll) {
    std::cout << s << std::endl;
}

std::map是按std::pair迭代的,所以要这样遍历std::map

std::map<std::string, std::string> mm;
for ( const auto& m : mm ) {
    std::cout  << m.first << " < " << m.second << ">" << std::endl;
}   

一般而言,如下一组基于范围的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仅用于说明,__RangeTexpression的类型,begin-exprend-expr则依据以下规则决定:

  1. 如果__RangeT是数组类型,则begin-exprend-expr分别等于__range__range + __bound,相应的__bound是数组边界。因此如此__RangeT是不知大小的数组,或者不完整类型(有声明没定义)的数组,那么程序就不合法。
  2. 如果__RangeT类型拥有begin()end()成员函数,则begin-exprend-expr分别等于__range.begin()__range.end()
  3. 否则,begin-exprend-expr分别等于begin(__range)end(__range),使用实参依赖查找算法进行查找,其实基本上就是std::begin()std::end()
  4. __begin__end具有相同的类型,在C++17中放宽了这个限制

目前C++标准库中所有容器,std::string和数组都能用这种基于范围的for循环遍历,如果想要让自己的数据结构也支持这种语法,需要满足以下要求:

  1. 能对此自定义数据结构类型调用beginend方法,无论是成员函数或者独立函数都可以,要能返回迭代器类型。
  2. 返回的迭代器类型必须支持operator*方法,operator!=方法和前缀形式的operator++方法,同样无论是成员函数或独立函数都可以。

相关链接

感觉不错,小额赞助一下!

Hosted by Coding Pages, 本站由 @missdeer 创建,由 Jekyll 于 2018-06-17 生成,感谢 CloudCannon 制作的theme: Edition ,感谢 Let's Encrypt 提供免费的SSL证书服务。本站点采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。© 2018