Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ non-iterator based range library?

I've been frustrated by the unhandiness of stl iterators and am looking for something more usable. In particular, a concept that is easier to map and filter, and one that is easier to implement too: basically C#/python/ruby/everything-but-C++ style enumerations.

I came across Andrei Alexandrescu's Iterator's must go! boostcon keynote of 2009 in which he describes a range concept that pretty much is exactly what I'm looking for and much more.

Does anybody know if something like this was actually implemented? I know of boost::range, but that's not an ideal solution; it's implemented in terms of iterators (which is more confusing and complex, less efficient, less general, and makes writing your own one at least as messy as implementing an iterator). Still, it's better than nothing. Is there anything better out there?

Edit: there's been lot's of discussion as to why this is at all attractive. On iteration explains the motivation more clearly. I realize the link to D - but that shouldn't distract from the argument itself.

like image 828
Eamon Nerbonne Avatar asked Dec 29 '10 22:12

Eamon Nerbonne


2 Answers

Seems pretty easy to do yourself -- assuming you don't mind a bit of work/typing

I haven't compiled this yet but something like this should move you a bit along

template< typename T>
class enumeration : boost::noncopyable {
virtual T& next() = 0;
virtual bool has_next() = 0;
};

template< typename T>
class editable_enumeration : public enumeration<T> {
virtual void remove() = 0;
}

//That was simple enough, now for adapting the std containers we
//will use the iterator interface already exposed. For new classes,
//we can implement iterators in any way we want. (e.g. copy python or java)

template < class C >
class const_std_enumeration : public enumeration<C::value_type>
{
protected:
C::const_iterator iter_;
C::const_iterator end_;

public:
typedef C::value_type value_type;

const_std_enumeration( C const& c) :
iter_(c.begin()), end_(c.end()) { } //c++0x use std::begin(c), std::end(c) instead

virtual value_type& next() { if(iter_!=end_) return *iter_++; throw std::runtime_error("No more elements"); }
virtual bool has_next() { return iter_!=end_; }
};

template < class C>
class std_enumeration : public enumeration<C::value_type>
{
protected:
C& c_;
C::iterator iter_;
C::iterator end_;

public:
typedef C::value_type value_type;

std_enumeration( C& c) :
c_(c), iter_(vector.begin()), end_(vector.end()) { }

virtual value_type& next() { if(v_!=end_) return *iter_++; throw std::runtime_error("No more elements"); }
virtual bool has_next() { return iter_!=end_; }
virtual remove() { iter_ = c_.erase(iter_); }
};


//Since we can't add methods to std containers, we will use an
//overloaded free-function `enumeration` to get enumerations from ANY container
//We could use `auto_ptr` or `unique_ptr`, but for simplicity's sake, I'm
//just using raw pointers

template < class C >
editable_enumeration<C::value_type>* enumeration( C&c ) { return new std_enumeration<C>(c); }

template < class C >
enumeration<C::value_type>* enumeration( C const& c ) { return new const_std_enumeration<C>(c); }

for all other containers, merely ensure that enumeration is defined and returns either an enumeration or editable_enumeration. If you other container already implements the iterator interface, then this should work

We can now write:

template<typename T>
bool contains( enumeration<T>* e, T const& t) {
while(e->has_next())
  if ( t == e->next() )
    return true;
return false;
}
...
std::vector<int> v = getIntVector();
if( contains( enumeration(v), 10 ) ) std::cout<<"Enumeration contains 10\n";
std::list<int> l = getIntList();
if( contains( enumeration(l), 10 ) ) std::cout<<"Enumeration contains 10\n";

It should be noted one huge advantage the iterator concept holds over this is the case where the next element is requested when then has_next() would return false. For iterators, end()++ is (IIRC) undefined behavior. For teh enumeration, it is defined to throw std::runtime_error(...) which may be worse for some people.

like image 107
KitsuneYMG Avatar answered Oct 14 '22 00:10

KitsuneYMG


May be this one will help you: http://rangelib.synesis.com.au/ .

like image 39
abyss.7 Avatar answered Oct 14 '22 00:10

abyss.7