Begin(), end() раздражение в алгоритмах STL

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

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

Литература:

...

Ответ 3

#define ALL(x) (x).begin(), (x).end()

sort(ALL(vec));

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

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()!

Ответ 7

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

Ответ 8

boost:: range_ex разрешит это до С++ 0x.

И это не сложно написать несколько оберток сами тем временем.