On 09-Aug-15 1:27 AM, K. Frank wrote:
>
> The new "for" syntax is convenient for iterating
> over collections:
>
> for (auto x : collection) // do stuff with x;
>
> But lots of times you want to give slightly special
> treatment to the first or last element:
>
> for (unsigned i = 0; i < collection.size(); i++) {
> if (i == 0) // do something special;
> if (i == 0) continue; // or don't do something
> // do stuff with collection[i];
> if (i == collection.size() - 1) // do something special;
> }
The Python language has a nice idiom for this, namely passing the range
you want to an `enumerate` function that produces an (index, value) pair
for each value from that range. Defined as a continuation it's pretty
simple,
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
The Boost library provides similar functionality for C++, although with
a silly pipe-syntax (it's a bit over-engineered), and hidden so well
that I couldn't find it now by simple googling. It's probably in the
vicinity of Boost ranges. But exactly where, that's the question.
However, I was able to find a similar utility that I just wrote up for
an answer to some forum question, apparently in comp.lang.c++ (this
group) and evidently this year:
<code file="Indexer.hpp">
#pragma once
// Copyright (c) 2015 Alf P. Steinbach
#include <iterator> // std::iterator_traits
#include <stddef.h> // ptrdiff_t
#include <type_traits> // std::remove_reference
#include <utility> // std::pair, std::declval, std::begin,
std::end, std::move
namespace progrock{ namespace cppx{
using std::begin;
using std::declval;
using std::end;
using std::iterator;
using std::iterator_traits;
using std::move;
using std::pair;
using std::random_access_iterator_tag;
using std::remove_reference;
using Index = ptrdiff_t;
template< class Underlying_iter_tp, class Index_tp = Index >
class Indexer
{
public:
using Underlying_iter = Underlying_iter_tp;
using Index = Index_tp;
using Item = typename remove_reference<decltype((
*declval<Underlying_iter>() ))>::type;
struct Numbered_item
: pair<Index, Item*>
{
using Pair = pair<Index, Item*>;
using Pair::pair; // Constructors.
using Pair::first;
using Pair::second;
auto index() const -> Index { return first; }
auto value() -> Item& { return *second; }
auto value() const -> Item const& { return *second; }
};
private:
Underlying_iter under_begin_;
Underlying_iter under_end_;
class Iter
: public iterator<
typename
iterator_traits<Underlying_iter>::iterator_category,
Numbered_item,
typename iterator_traits<Underlying_iter>::difference_type,
typename iterator_traits<Underlying_iter>::pointer,
typename iterator_traits<Underlying_iter>::reference
>
{
friend class Indexer;
private:
Underlying_iter it_;
Numbered_item item_;
Iter( Underlying_iter it )
: it_( move( it ) )
, item_( 0, &*it ) // TODO: Check validity
{}
public:
friend
auto operator<( Iter const& a, Iter const& b )
-> bool
{ return (a.it_ < b.it_); }
friend
auto operator<=( Iter const& a, Iter const& b )
-> bool
{ return (a.it_ <= b.it_); }
friend
auto operator==( Iter const& a, Iter const& b )
-> bool
{ return (a.it_ == b.it_); }
friend
auto operator>=( Iter const& a, Iter const& b )
-> bool
{ return (a.it_ >= b.it_); }
friend
auto operator>( Iter const& a, Iter const& b )
-> bool
{ return (a.it_ > b.it_); }
friend
auto operator!=( Iter const& a, Iter const& b )
-> bool
{ return (a.it_ != b.it_); }
auto operator++()
-> Iter&
{
++it_;
++item_.first; item_.second = &*it_;
return *this;
}
auto operator++( int )
-> Iter
{
Iter original = *this;
++*this;
return original;
}
auto operator*()
-> Numbered_item const&
{ return item_; }
};
public:
auto begin() -> Iter { return Iter( under_begin_ ); }
auto end() -> Iter { return Iter( under_end_ ); }
Indexer( Underlying_iter const begin_iter, Underlying_iter
const end_iter )
: under_begin_( begin_iter )
, under_end_( end_iter )
{}
};
template< class Collection_tp >
auto indexed( Collection_tp& c )
-> Indexer<decltype( begin( c ) )>
{ return Indexer<decltype( begin( c ) )>( begin( c ), end( c ) ); }
}} // namespace progrock::cppx
</code>
I'm pretty sure that this has not been tested for anything but the
simplest possible example, in the original question, whatever it was.
And I would usully not define explicitly all those comparison operators,
but instead inherit a template that generates them.
So, it's more like example proof-of-concept code than something to use
directly as-is, but I think you may be able to at least at first just
use it directly.
> As a concrete (and common) example, suppose you want
> to print out a vector in parenthesized, comma-separated
> notation:
>
> (1, 2, 3, 4, 5)
>
> Is there a nice idiom for this using "for (auto x : y)"?
<code>
#include <p/cppx/collections/Indexer.hpp>
using namespace progrock;
#include <iostream>
#include <vector>
using namespace std;
auto main() -> int
{
using cppx::indexed;
vector<int> const v = {1, 2, 3, 4, 5};
wcout << "(";
for( auto item : indexed( v ) )
{
wcout << (item.index() > 0? ", " : "") << item.value();
}
wcout << ")" << endl;
}
</code>
<snip>
Cheers & hth.,
- Alf
--
Using Thunderbird as Usenet client, Eternal September as NNTP server.