Существует ли C ++ эквивалент Java-интерфейса Collection для классов контейнеров STL? - PullRequest
3 голосов
/ 22 июня 2010

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

Первое решение, которое приходит мне в голову, - это интерфейс (назовем его CollectionInterface), реализованный классами, которые обернут контейнеры STL.поэтому объявление функции будет выглядеть так:

f(const CollectionInterface * collection);

Или я думал о шаблоне метода, который имеет преимущество в том, что он сохраняет привязку во время компиляции:

template <class CONTAINER> void f(const CONTAINER & collection);

Какой способты считаешь лучше?

Ответы [ 3 ]

7 голосов
/ 22 июня 2010

ForwardIterator ?Это тип InputIterator (или OutputIterator), который также допускает многопроходные алгоритмы (увеличение его не отменяет предыдущие значения).

Итераторы (которые сильно отличаются от итераторов Java)центральный поток, объединяющий коллекции C ++.Для примеров алгоритмов, работающих над ними (и связанных с ними требований к типу итераторов), вы можете начать с <algorithm>.В частности, search предоставляет пример использования ForwardIterator.Он находит первое вхождение в диапазоне [first1, last1] последовательности, определенной в диапазоне [first2, last2).Это все объекты, отвечающие требованиям ForwardIterator.

4 голосов
/ 22 июня 2010

Я хотел бы передать произвольный контейнер в качестве аргумента функции и выполнить итерацию по нему (без стирания или выталкивания элементов).

Передача итераторов. Вот пример для реализации и использования:

template <typename Iter>
void function(Iter begin, Iter end)
{
    for (Iter it = begin; it != end; ++it)
    {
        std::cout << *it << std::endl;
    }
}

int main()
{
    std::string array[] = {"hello", "array", "world"};
    function(array, array + 3);

    std::vector<std::string> vec = {"hello", "vector", "world"};
    function(vec.begin(), vec.end());
}

Обратите внимание, что во многих случаях вам на самом деле не нужно писать функцию, но вы можете создать ее, используя вместо этого библиотечные средства, а затем просто применить std::for_each к ней. Или, что еще лучше, используйте существующий алгоритм, такой как std::accumulate или std::find_if.

4 голосов
/ 22 июня 2010

Вы также можете написать методы, которые принимают весь контейнер вместо ссылки, если вы так хотите обрабатывать вещи. Все итераторы в стандартные библиотечные контейнеры предоставляются через функции-члены begin() и end(), а в некоторых случаях rbegin() и rend() для итерации в обратном направлении. То, как работают шаблоны, вам не нужно создавать фактический тип интерфейса, из которого происходят объекты; требования вместо этого выводятся объектом, который используется.

template<typename Container> void Function(const Container& c) {
    for(typename Container::const_iterator i = c.begin(), end = c.end(); i != end; ++i)
       //do something
}

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

...