begin (), end () раздражение в алгоритмах STL - PullRequest
16 голосов
/ 29 марта 2009

Мне нравятся алгоритмы STL, и я предпочитаю использовать алгоритмы, а не обычные циклы.
Почти все алгоритмы STL обычно используются как:

std::algorithm_name( container.begin(), container.end(), ..... )  

container.begin(), container.end() - одна из самых популярных пар слов в моих проектах.

У кого-нибудь есть такая же проблема?
Как вы, ребята, решаете эту проблему?
Что бы вы могли предложить, чтобы избежать этого дублирования? Я вижу несколько путей решения, но все они имеют разные ограничения (использование макросов, несовместимость с обычными указателями и т.

Ответы [ 8 ]

28 голосов
/ 29 марта 2009

Следующий стандарт C ++, C ++ 0X (где X означает, надеюсь, 9), добавит возможность перехода от перспективы итератора к перспективе контейнера. Вы сможете сделать, например.

станд :: сортировать (my_vec);

Если вы не можете дождаться этого, я бы порекомендовал вам посмотреть: Boost.Range

И если вы действительно заинтересованы в итераторах / диапазонах, я бы порекомендовал вам прочитать " от итераторов Андрея должно идти

19 голосов
/ 29 марта 2009

Многие сталкивались с этой неприятностью. Хотя концепция итератора является исключительно общей, ей не хватает некоторого удобства использования.

Введите понятие «диапазон». Желательно избегать любого дублирования кода. Поэтому, если вы встретите пары .begin () и .end () по всему коду, рекомендуется создать слой между «получением итератора» и фактическими алгоритмами.

Ссылки:

...

7 голосов
/ 29 марта 2009
#define ALL(x) (x).begin(), (x).end()

sort(ALL(vec));
3 голосов
/ 10 мая 2009

Эта прекрасная презентация [PDF] о возможном будущем решении этой проблемы была недавно связана с Reddit здесь обсуждается, как полностью заменить итераторы концепцией диапазона.

3 голосов
/ 29 марта 2009

Если бы получилось очень плохо , я бы, вероятно, создал бы набор шаблонов для моих наиболее часто используемых алгоритмов в новом пространстве имен:

namespace my_ranged_algorithms {
    // Metafunction for extracting an appropriate iterator from
    // the container type
    template <typename T>
    struct get_iterator_type_for;

    // For vectors
    template <typename T>
    struct get_iterator_type_for<std::vector<T> > {
        typedef typename std::vector<T>::iterator type;
    };

    template <typename T>
    struct get_iterator_type_for<std::vector<T> const> {
        typedef typename std::vector<T>::const_iterator type;
    };

    // For C arrays
    template <typename T, size_t N>
    struct get_iterator_type_for<T(&)[N]> {
        typedef T* type;
    };

    // Generic begin() and end() wrappers

    // For all standard containers        
    template <typename Cont>
    typename get_iterator_type_for<Cont>::type begin(Cont& c) {
        return c.begin();
    }

    template <typename Cont>
    typename get_iterator_type_for<Cont>::type end(Cont& c) {
        return c.end();
    }

    // For C arrays
    template <typename T, size_t N>
    typename get_iterator_type_for<T (&)[N]>::type begin(T (&c)[N]) {
        return c;
    }

    template <typename T, size_t N>
    typename get_iterator_type_for<T (&)[N]>::type end(T (&c)[N]) {
        return c + N;
    }

    // Finally, the actual algorithm wrappers

    // copy
    template <typename Cont, typename OutIter>
    OutIter copy(Cont& from, OutIter to) {
        return std::copy(begin(from), end(from), to);
    }

    // remove
    template <typename Cont, typename T>
    typename get_iterator_type_for<Cont>::type remove(Cont& from, T x) {
        return std::remove(begin(from), end(from), x);
    }

    // etc.
};

Тогда назовите их так:

vector<int> a, b;
using namespace my_ranged_algorithms;

copy(a, back_inserter(b));
b.erase(remove(b, 42), b.end()); // Remember to call erase() after remove()!
3 голосов
/ 29 марта 2009

Во-первых, я не думаю, что это большая проблема. В общем, я не очень хочу печатать еще несколько символов. удобочитаемость важнее, и я думаю, что начало / конец отлично читаются.

Могут помочь более короткие имена контейнеров (con.begin () легче набирать, чем container.begin ())

И передача итераторов вместо самого контейнера означает, что вам не нужно вызывать начало / конец более одного раза.

Это не то, что беспокоит меня.

3 голосов
/ 29 марта 2009

C ++ 11 устраняет эту незначительную неприятность в языке.

1 голос
/ 17 апреля 2009

boost :: range_ex решит эту проблему до c ++ 0x.

А пока не сложно написать несколько оберток самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...