C++中循环语法糖的简写(11)

Shorthand for for-loop - syntactic sugar in C++(11)

本文关键字:循环 语法 C++      更新时间:2023-10-16

实际上这是两个相关的问题。

我知道C++11中有一种新的语法,用于基于范围的for循环形式:

//v is some container
for (auto &i: v){
   // Do something with i
}

第一个问题:我如何推断我在这个循环中的哪个迭代?(假设我想在位置j用值j填充一个向量)。

第二个问题:我想知道是否还有其他方法可以编写形式的循环

for (int i=0; i<100; i++) { ... }

我觉得这种写法有点麻烦,而且我经常这样做,我希望有一个更简洁的语法。大致如下:

for(i in [0..99]){ ... }

那就太好了。

对于这两个问题,我都希望避免使用额外的库。

第一个答案:你没有。你为了一个简单的目的使用了一个简单结构;如果你有更复杂的需求,你就需要更复杂的东西。

第二个答案:您可以创建一个迭代器类型来产生连续的整数值,以及一个"容器"类型来提供这些值的范围。除非你有充分的理由自己做,否则Boost有这样一件事:

#include <boost/range/irange.hpp>
for (int i : boost::irange(0,100)) {
    // i goes from 0 to 99 inclusive
}

使用此:

size_t pos = 0;
for (auto& i : v) {
    i = pos;
    ++pos;
}

(Boost是好的,但它不是普遍接受的。)

对于第一个问题,答案很简单:如果你需要迭代次数,不要使用抽象掉迭代次数的语法结构。只需使用普通的for循环,而不是基于范围的循环。

对于第二个问题,我认为标准库中目前没有任何内容,但您可以使用boost::irange

for (int i : boost::irange(0, 100))

对于第二个问题-如果Boost太重,您可以始终使用以下库:

  • cppitertools

for(auto i : range(10, 15)) { cout << i << 'n'; }将打印10 11 12 13 14

for(auto i : range(20, 30, 2)) { cout << i << 'n'; }将打印20 22 24 26 28

也支持双精度和其他数字类型。

它有其他Python迭代工具,并且只是头。

您可以使用Boost.Range同时完成这两件事:http://boost.org/libs/range

  • CCD_ 8:元素值&索引
  • boost::irange:整数范围

为了简洁起见(并且为了增加趣味性,因为boost::irange已经单独演示过了),下面是一个示例代码,演示了这些功能的协同工作:

// boost::adaptors::indexed
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/adaptors/reference/indexed.html
#include <boost/range/adaptor/indexed.hpp>
// boost::irange
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/ranges/irange.html
#include <boost/range/irange.hpp>
#include <iostream>
#include <vector>
int main()
{
    std::vector<int> input{11, 22, 33, 44, 55};
    std::cout << "boost::adaptors::indexed" << 'n';
    for (const auto & element : input | boost::adaptors::indexed())
    {
        std::cout << "Value = " << element.value()
                  << " Index = " << element.index()
                  << 'n';
    }
    endl(std::cout);
    std::cout << "boost::irange" << 'n';
    for (const auto & element : boost::irange(0, 5) | boost::adaptors::indexed(100))
    {
        std::cout << "Value = " << element.value()
                  << " Index = " << element.index()
                  << 'n';
    }
    return 0;
}

样本输出:

boost::adaptors::indexed
Value = 11 Index = 0
Value = 22 Index = 1
Value = 33 Index = 2
Value = 44 Index = 3
Value = 55 Index = 4
boost::irange
Value = 0 Index = 100
Value = 1 Index = 101
Value = 2 Index = 102
Value = 3 Index = 103
Value = 4 Index = 104

如果v是矢量(或任何std连续容器),则

for(auto& x : v ) {
  size_t i = &x-v.data();
  x = i;
}

将第i个条目设置为值CCD_ 13。

计数的输出迭代器相当容易编写。Boost有一个,并且有一个易于生成的范围,称为irange

提取容器的索引相对容易。我已经编写了一个名为indexes的函数,它可以接受一个容器或一系列整数,并在所讨论的范围内生成随机输出迭代器。

这给了你:

for (size_t i : indexes(v) ) {
  v[i] = i;
}

Boost中可能有一个等价的容器来索引范围函数。

如果你两者都需要,又不想做这项工作,你可以写一个拉链。

for( auto z : zip( v, indexes(v) ) ) {
  auto& x = std::get<0>(z);
  size_t i = std::get<1>(z);
  x = i;
}

其中CCD_ 16采用两个或多个可迭代的范围(或容器),并在元素的CCD_。

这里是Boost zip迭代器:http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html--可能有一个Boost zip范围可以处理与上面的zip函数类似的语法。

对于第二个问题:

还有另一种方法,但我不会使用或推荐它。然而,为了快速设置测试,你可以写:

如果你不想使用库,并且只提供范围的上限就可以了,你可以写:

for (auto i:vector<bool>(10)) {
    cout << "x";
}

这将创建一个大小为10的布尔向量,其中包含未初始化的值。使用i循环这些单元化的值(因此不要使用i),它将打印10次"x"。

对于第二个问题,如果您使用的是最新的Visual Studio版本,请键入"if",然后键入TabTab以填充init值、step-up等。