有没有办法使用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 ) );
}
}
答案 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)
在c++17中有一些图书馆帮助,你可以让它工作:
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会让这更好。
在原始c++11中,不,你没有运气。