C ++ Не-итерационная библиотека диапазонов? - PullRequest
18 голосов
/ 30 декабря 2010

Я был разочарован простотой итераторов stl и ищу что-то более полезное. В частности, это концепция, которую легче отобразить и отфильтровать, и концепция, которую также легче реализовать: в основном перечисления в стиле C # / python / ruby ​​/ everything-but-C ++.

Я встречал у Андрея Александреску Итератора!

Кто-нибудь знает, было ли реализовано нечто подобное? Я знаю о boost :: range, но это не идеальное решение; он реализован в терминах итераторов (который более запутанный и сложный, менее эффективный, менее общий и делает написание своего собственного по меньшей мере таким же грязным, как реализация итератора). Тем не менее, это лучше, чем ничего. Есть ли что-нибудь лучше там?

Редактировать: Было много дискуссий о том, почему это вообще привлекательно. На итерации объясняет мотивацию более четко. Я понимаю связь с D - но это не должно отвлекать от самого аргумента.

Ответы [ 3 ]

5 голосов
/ 30 декабря 2010

Кажется, довольно легко сделать это самостоятельно - при условии, что вы не возражаете против небольшой работы / ввода

Я еще не скомпилировал это, но что-то вроде этого должно вас немного продвинуть

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); }

для всех других контейнеров, просто убедитесь, что enumeration определен и возвращает либо перечисление, либо editable_enumeration. Если ваш другой контейнер уже реализует интерфейс итератора, то это должно работать

Теперь мы можем написать:

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";

Следует отметить одно огромное преимущество, которое концепция итератора имеет над этим, - это случай, когда следующий элемент запрашивается, когда тогда has_next() возвращает false. Для итераторов end () ++ - это (IIRC) неопределенное поведение. Для перечисления он определен как throw std::runtime_error(...), что может быть хуже для некоторых людей.

2 голосов
/ 31 августа 2011

Может быть, этот вам поможет: http://rangelib.synesis.com.au/.

1 голос
/ 28 июля 2014

Прошло несколько лет, но, похоже, сейчас есть библиотека, которая реализует правильные последовательности функциональных стилей: Потоки C ++ .

Пример кода с домашней страницы проекта:

Суммирование первых 10 квадратов:

int total = stream::MakeStream::counter(1)
    .map([] (int x) { return x * x; })
    .limit(10)
    .sum();
...