In Python there is a built-in function `enumerated` that produces a
corresponding sequence of (index, value) pairs:
raw_array = [1.2, 3.4, 5.6]
for x in enumerate( raw_array ):
print( "%d -> %g" % (x[0], x[1]) )
How to do that in C++?
Well, Öö Tiib has already mentioned the Boost Range library's `indexed`,
and I would guess the Python `enumerate` facility served as inspiration
for that.
If you don't want a dependency on Boost, or if you just don't want the
over-engineered custom operator| thing, then it's not hard to do this
yourself, e.g. like the following -- I wrote this code in response to
your posting, so it's not been tested more than the little program:
<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<Index, Item*>::pair;
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
</file>
<file "main.cpp">
#include "Indexer.hpp"
using namespace progrock;
using cppx::indexed;
#include <iostream>
#include <array>
#include <list>
#include <vector>
using namespace std;
template< class Collection >
void display( Collection const& c )
{
for( auto const item : indexed( c ) )
{
wcout << item.index() << L" → " << item.value() << endl;
}
}
auto main() -> int
{
display( array<double, 3>{1.2, 3.4, 5.6} );
wcout << endl;
display( vector<double>{1.2, 3.4, 5.6} );
wcout << endl;
display( list<double>{1.2, 3.4, 5.6} );
wcout << endl;
vector<double> v(5);
for( auto item : indexed( v ) )
{
item.value() = 0.1*item.index();
}
display( v );
}
</file>
The little arrow in the output may be displayed incorrectly or may cause
truncation of the output. One fix is to replace it with "->", which has
only ASCII characters. Another fix is to configure the C++ i/o properly,
which, sadly, is not done by default by current implementations; for
code that does this see e.g.
<url:
http://stackoverflow.com/questions/30197758/how-can-i-make-unicode-iostream-i-o-work-in-both-windows-and-unix-land>
And if you want to display that little arrow with Python in Windows
consoles, see e.g.
<url:
https://alfps.wordpress.com/2015/05/12/non-crashing-python-3-x-output-in-windows/>
Cheers & hth.,
- Alf
--
Using Thunderbird as Usenet client, Eternal September as NNTP server.