如何使用C ++ 11的顺序对的范围语法?

时间:2017-11-13 21:10:29

标签: c++ c++11

有没有办法使用for-range循环语法来处理数组中的两个连续元素?

示例...

func( std::vector< vec2 > &points )
{
std::vector< float > distances;
for( int i = 0; i < (int)points.size() - 1; i++ )
   {
   auto from = points.at( i );
   auto to   = points.at( i + 1 );

   distances.push_back( magnitude( to - from ) );
   }
}

2 个答案:

答案 0 :(得分:4)

  

有没有办法使用for-range循环语法来处理数组中的两个连续元素?

没有开箱即用。

但是,您可以使用自己的包装器类和迭代器类来获取所需的内容。

包装类的begin()end()成员函数必须返回一个迭代器,当使用std::pair运算符取消引用时,该迭代器的计算结果为*

这是一个示范性计划:

#include <iostream>
#include <vector>

struct VectorWrapper;

struct MyIterator
{
   MyIterator(VectorWrapper const& wrapper, size_t index) : wrapper_(wrapper), index_(index) {}

   std::pair<float, float> operator*();

   MyIterator& operator++()
   {
      ++index_;
      return *this;
   }

   bool operator==(MyIterator const& rhs) const
   {
      return (this->index_ == rhs.index_);
   }

   bool operator!=(MyIterator const& rhs) const
   {
      return (this->index_ != rhs.index_);
   }

   VectorWrapper const& wrapper_;
   size_t index_;
};

struct VectorWrapper
{
   explicit VectorWrapper(std::vector<float>& distances) : distances_(distances) {}

   MyIterator begin() const
   {
      return MyIterator(*this, 0);
   }

   MyIterator end() const
   {
      return MyIterator(*this, distances_.size()-1);
   }

   std::vector<float>& distances_;
};

std::pair<float, float> MyIterator::operator*()
{
   return std::make_pair(wrapper_.distances_[index_], wrapper_.distances_[index_+1]); 
}

int main()
{
   std::vector<float> dist = {1, 2, 3, 4, 5, 6};
   VectorWrapper wrapper(dist);
   for ( auto item : wrapper )
   {
      std::cout << item.first << ", " << item.second << std::endl;
   }
}

及其输出:

1, 2
2, 3
3, 4
4, 5
5, 6

答案 1 :(得分:1)

中有一些图书馆帮助,你可以让它工作:

for (auto&&[ from, to ] : adjacent_overlapped_zip( points ) ) {
  distances.push_back( magnitude( to-from) );
}

其中adjacent_overlapped_zip返回一对广告对或点组的广告迭代器。

template<class It>
struct range {
  It b; It e;
  It begin() const{ return b; }
  It end() const{ return e; }
  bool empty() const{ return begin()==end(); }
  range without_front( std::size_t n = 1 ) const {
    return {std::next(begin(), n), end()};
  }
  range without_back( std::size_t n = 1 ) const {
    return {begin(), std::prev(end(), n)};
  }
};
template<class It>
range(It b, It e)->range<It>;

template<class It>
struct adjacent_iterator:It {
  auto operator*()const {
    return std::make_pair( It::operator*(), std::next(*this).It::operator*() );
  }
  using It::It;
  explicit adjacent_iterator(It it):It(it) {}
};
template<class It>
explicit adjacent_iterator( It ) -> adjacent_iterator<It>;

// TODO: support pointers

template<class C>
auto adjacent_overlapped_zip( C& c ) {
  using std::begin; using std::end;
  range r( begin(c), end(c) );
  if (!r.empty()) {
    r = r.without_back();
    range retval( adjacent_iterator(r.begin()), adjacent_iterator(r.end()) );
    return retval;
  } else {
    return {};
  }
}

或类似的东西。上面的代码可能包含拼写错误和其他错误。

我也会受到诱惑:

for (auto&&[ from, to ] : transform( [](auto it){ return std::make_pair( *it, *std::next(it)); }, range( iterators_of( points ) ).without_back() ) )
  distances.push_back( magnitude( to-from) );
}

有一组稍微更原始的原语。 Ranges-v3会让这更好。

在原始中,不,你没有运气。