2

I would like a C++ constructor/method to be able to take any container as argument. In C# this would be easy by using IEnumerable, is there an equivalent in C++/STL ?

Anthony

BlueTrin
  • 9,610
  • 12
  • 49
  • 78

3 Answers3

6

The C++ way to do this is with iterators. Just like all the <algorithm> functions that take (it begin, it end, ) as first two parameters.

template <class IT>
T foo(IT first, IT last)
{
    return std::accumulate(first, last, T());
}

If you really want to go passing the container itself to the function, you have to use 'template template' parameters. This is due to the fact that C++ standard library containers are not only templated with the type of the contained type, but also with an allocator type, that have a default value and is therefore implicit and not known.

#include <vector>
#include <list>
#include <numeric>
#include <iostream>

template <class T, class A, template <class T, class A> class CONT>
T foo(CONT<T, A> &cont)
{
    return std::accumulate(cont.begin(), cont.end(), T());
}

int main()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    std::list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);

    std::cout << foo(v) << " " << foo(l) << "\n";

    return 0;
}
Didier Trosset
  • 36,376
  • 13
  • 83
  • 122
  • 1
    Also it's pretty rare for it to be useful to take a Container generically. The only member functions for a Container are begin, end, size, max_size, empty, and swap. If you have the begin/end iterators, you can do all of these except max_size (which is almost useless) and swap, although size might be much slower using the iterators. Containers also have various types, most of which you can get from the iterator_traits of the iterator. So taking any Container mostly just saves typing. Being a bit more specific (taking a Sequence, for instace) might be more useful. – Steve Jessop Dec 17 '09 at 11:57
1

Depends what you want to do with the container. One thought: just pass an iterator if you want to access what is stored in the container.

user231967
  • 1,935
  • 11
  • 9
1

A good question, +1. What a pity, its two years old... I post an answer anyway: You're stuck with the "C++ way" if you only want to expose an interface of your library. My way to do that is this:

template<class TValue>
class IEnumerator {
 public:
  virtual bool MoveNext() = 0;
  vírtual TValue Current() = 0;
  virtual void Reset() = 0;
};

template<class TValue>
class IEnumerable {
 public:
  virtual std::unique_ptr< IEnumerator<TValue> > GetEnumerator() const = 0;
};

This way, you can write APIs of the following kind:

void MyAPI(const IEnumerable<IMyLibAPIObject>& pSequence);

Of course, I provide different implementations like StlEnumerator or StlEnumerable, or EnumeratorAdaptor<T, U> to get covariance as in C#...

Cheers,

Paul

Edit: So far I ended up with a type erasing 'AnyEnumerator' and 'AnyEnumerable'. Also, I am how aware of the various 'any_iterator' implementations...

Paul Michalik
  • 4,331
  • 16
  • 18