views:

94

answers:

3

I would like to pass arbitrary container as an argument of function and iterate over it (no erasing nor pushing elements). Unfortunately it looks like there is no standard way of doing this.

First solution which comes to my mind is an interface (let's call it CollectionInterface) implemented by classes that will wrap STL containers. so the function declaration would look like:

f(const CollectionInterface * collection);

Or, I was thinking about method template, which has an advantage that it keeps binding at compilation time:

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

Which way do you think is better?

+7  A: 

ForwardIterator? This is a type of InputIterator (or OutputIterator) that also allows multi-pass algorithms (incrementing it does not invalidate prior values).

Iterators (which are quite different from Java iterators) are the central thread unifying C++ collections. For examples of algorithms working on them (and associated iterator type requirements), you can start with <algorithm>. In particular, search provides an example of using ForwardIterator. It finds the first occurrence within the range [first1, last1] of the sequence defined by the range [first2, last2). These are all objects meeting the requirements of ForwardIterator.

Matthew Flaschen
As a parameter for a method template?
doc
@doc: For template functions, either member or free-standing - free functions are often preferred in C++ if it doesn't have to be a member function.
Georg Fritzsche
+2  A: 

You can also write methods that accept the entire container instead of a reference if that's the way you want to handle things. Iterators into standard library containers are all provided via the member functions begin() and end(), or in some cases rbegin() and rend() for iterating backwards. The way templates work, you don't have to create an actual interface type that objects derive from; the requirements are instead inferred by the object is used.

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

Passing iterators provide more flexibility when using the functions, particularly in that not all iterators come from containers with explicit begin() and end() functions, and you can provide whatever explicit subrange you want. But sometimes this method is appropriate.

Dennis Zickefoose
+4  A: 

I would like to pass arbitrary container as an argument of function and iterate over it (no erasing nor pushing elements).

Pass iterators. Here is an example for implementation and use:

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

Note that in many cases, you don't actually need to write the function, but you can compose it using the library facilities instead and then simply apply std::for_each on that. Or even better, use a preexisting algorithm like std::accumulate or std::find_if.

FredOverflow