Or is it safe to use vector if the Enumerator of T is just listing all the elements?
IEnumerable<T> is the base interface for collections in the System. Collections. Generic namespace such as List<T>, Dictionary<TKey,TValue>, and Stack<T> and other generic collections such as ObservableCollection<T> and ConcurrentStack<T>.
IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. It is the base interface for all non-generic collections that can be enumerated. This works for read-only access to a collection that implements that IEnumerable can be used with a foreach statement.
What is IEnumerable in C#? IEnumerable in C# is an interface that defines one method, GetEnumerator which returns an IEnumerator interface. This allows readonly access to a collection then a collection that implements IEnumerable can be used with a for-each statement.
In C#, an Enumerable is an object like an array, list, or any other sort of collection that implements the IEnumerable interface. Enumerables standardize looping over collections, and enables the use of LINQ query syntax, as well as other useful extension methods like List.
It isn't needed in C++, and here's why:
C# only supports dynamic polymorphism. So to create a reusable algorithm, you need an interface which all iterators will implement. That's IEnumerator<T>
, and IEnumerable<T>
is a factory for returning an iterator.
C++ templates, on the other hand, support duck typing. That means you don't need to constrain a generic type parameter by an interface in order to access members -- the compiler will look up members by name for each individual instantiation of the template.
C++ containers and iterators have implicit interfaces which is equivalent to .NET IEnumerable<T>
, IEnumerator<T>
, ICollection<T>
, IList<T>
, namely:
For containers:
iterator
and const_iterator
typedefsbegin()
member function -- fills the need for IEnumerable<T>::GetEnumerator()
end()
member function -- instead of IEnumerator<T>::MoveNext()
return valueFor forward iterators:
value_type
typedefoperator++
-- instead of IEnumerator<T>::MoveNext()
operator*
and operator->
-- instead of IEnumerator<T>::Current
operator*
-- instead of IList<T>
indexer setteroperator==
and operator!=
-- no true equivalent in .NET, but with container's end()
matches IEnumerator<T>::MoveNext()
return valueFor random access iterators:
operator+
, operator-
, operator[]
-- instead of IList<T>
If you define these, then standard algorithms will work with your container and iterator. No interface is needed, no virtual functions are needed. Not using virtual functions makes C++ generic code faster than equivalent .NET code, sometimes much faster.
Note: when writing generic algorithms, it's best to use std::begin(container)
and std::end(container)
instead of the container member functions. That allows your algorithm to be used with raw arrays (which don't have member functions) in addition to the STL containers. Raw arrays and raw pointers satisfy all other requirements of containers and iterators, with this single exception.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With