是否可以替换(自动 i=0;i<n;i++) ... with for(auto i:<something>) 而不使用向量?

Is it possible to replace for(auto i=0;i<n;i++) ... with a for(auto i:<something>) without using a vector?

本文关键字:lt something gt 向量 auto i++ 自动 替换 with 是否 for      更新时间:2023-10-16

我想替换一个简单的 for 循环:

for (auto i=0;i<n;i++) {
  whatever;
}

使用以下形式的迭代器:

for (auto i: <something>) ...

我知道可以用向量来完成,但我不想声明一个向量(并填充它)。

从理论上讲,我想要这样简单的东西:

for (auto i: 1..n) ... 

这可能吗?

谢谢。

没有内置的解决方案。

如果需要,可以使用如下Boost.counting_range:

#include <iostream>
#include <boost/range/counting_range.hpp>
int main() {
    for (auto v : boost::counting_range(2,13))
        std::cout << v << "n";
}

(直播)或自己滚动。提升范围不会保存所有数字,而是包装一对迭代器。(在概念上类似于 Python2 xrange或 Python3 range

现在,这是否比手动编写循环更容易/更好,由读者决定。


附录:如果你想推出自己的解决方案,请编写一些迭代器,在取消引用时返回一个数字,在增量时增加内部数字,如果内部数字相等,则比较相等。然后编写一个包装类,该类提供beginend函数以返回此类迭代器。

Boost.counting_iterator是此类迭代器的实现,Boost.counting_range将其包装为如上所示的范围。

template<class T>
struct index_it{
  T t;
  void operator++(){++t;}
  T operator*()const{ return t; }
  friend bool operator==(index_it const& lhs,index_it const& rhs){
    return lhs.t==rhs.t;
  }
  friend bool operator!=(index_it const& lhs,index_it const& rhs){
    return lhs.t!=rhs.t;
  }
};
template<class T>
index_it<T> index(T t){return {t}; }

这是一个非常小的索引"迭代器"。 它不是真正的迭代器,因为它违反了他们的公理:但它保证足以进行for(:)循环。

template<class It>
struct range_t{
  It b,e;
  It begin()const{return b;}
  It end()const{return e;}
};
template<class It>
range_t<It> range(It b, It e){ return {b,e}; }

是一个非常小的范围,符合for(:)循环的条件。

template<class Scalar>
auto indexes(Scalar b, Scalar e){
  return range(index(b),index(e));
}

创建一系列索引。

用:

for(auto i:indexes<int>(0,n))

为了好玩,这也给了我们:

template<class R>
auto iterators(R& r){
  using std::begin; using std::end;
  return indexes( begin(r), end(r) );
}

这使您可以像这样迭代容器或范围的有效迭代器。 一旦你弄清楚index_it到底是什么,问题就是一样的!

for(auto it:iterators(vec))

活生生的例子。

没有内置的解决方案。就这样。


您可以为自己定义类似的东西,如下所示:

#include<functional>
#include<cstddef>
#include<array>
#include<iostream>
template<std::size_t... I>
constexpr auto seq(std::integer_sequence<std::size_t, I...>) {
    return std::array<std::size_t, sizeof...(I)>{ I... };
}
template<std::size_t N>
constexpr auto seq() {
    return seq(std::make_index_sequence<N>());
}
int main() {
    for(auto i: seq<10>()) {
        std::cout << i << std::endl;
    }
}

如果要处理 0 到 N 以外的范围,可以改为执行以下操作:

#include<functional>
#include<cstddef>
#include<array>
#include<iostream>
template<std::size_t N, std::size_t... I>
constexpr auto seq(std::integer_sequence<std::size_t, I...>) {
    return std::array<std::size_t, sizeof...(I)>{ (N+I)... };
}
template<std::size_t N, std::size_t M, std::enable_if_t<(N<M)>* = nullptr>
constexpr auto seq() {
    return seq<N>(std::make_index_sequence<M-N>());
}
int main() {
    for(auto i: seq<3, 7>()) {
        std::cout << i << std::endl;
    }
}

请注意,此解决方案需要 C++14 修订版。


另一个不需要实例化数据结构的解决方案是以下解决方案:

#include<functional>
#include<cstddef>
#include<array>
#include<iostream>
#include<utility>
template<std::size_t N, typename F, std::size_t... I>
constexpr void seq(F &&f, std::integer_sequence<std::size_t, I...>) {
    int arr[] = { (std::forward<F>(f)(I+N), 0)... };
}
template<std::size_t N, std::size_t M, typename F, std::enable_if_t<(N<M)>* = nullptr>
constexpr void seq(F &&f) {
    seq<N>(std::forward<F>(f), std::make_index_sequence<M-N>());
}
int main() {
    seq<3, 7>([](int i){ 
        std::cout << i << std::endl;
    });
}

arr可能会被编译器清除,但它看起来不太像 for 循环。