class X {
public:
typedef std::list Container;
// (1)
const Container& GetElements() const;
// (2)
Container::iterator Element
If you can use Boost, there is a library for you: http://www.boost.org/doc/libs/1_47_0/libs/iterator/doc/index.html Specifically look at iterator_facade and iterator_adapter
Here is an example of what to do - It provides an std::vector holder, with STL compatible iterators. You can extend it by adding other methods, like operator[], size(), push_back() etc.
template class VectorHolder { public: typedef T value_type;
public: VectorHolder() : m_values() { }
public: typedef typename std::vector::iterator vector_iterator; typedef typename std::vector::const_iterator vector_const_iterator;
class iterator : public boost::iterator_adaptor<iterator, vector_iterator>
{
public:
iterator()
: iterator::iterator_adaptor_()
{
}
iterator(const vector_iterator& it)
: iterator::iterator_adaptor_(it)
{
}
private:
friend class boost::iterator_core_access;
};
class const_iterator : public boost::iterator_adaptor<const_iterator, vector_const_iterator>
{
public:
const_iterator()
: const_iterator::iterator_adaptor_()
{
}
const_iterator(const vector_const_iterator& it)
: const_iterator::iterator_adaptor_(it)
{
}
const_iterator(const iterator& it)
: const_iterator::iterator_adaptor_(it.base())
{
}
private:
friend class boost::iterator_core_access;
};
iterator begin()
{
return iterator(m_values.begin());
}
iterator end()
{
return iterator(m_values.end());
}
const_iterator begin() const
{
return const_iterator(m_values.begin());
}
const_iterator end() const
{
return const_iterator(m_values.end());
}protected:
std::vector<T> m_values;};
Off course, the simplest is this :
class X {
public:
typedef std::list<int> Container;
Container m_container;
};
but that makes your class X
obsolete.
Other then that, if you really like your class, then add next methods :
Container::const_iterator ElementBegin() const;
Container::const_iterator ElementEnd() const;
int size() const;
I would use these names instead : iterator
, const_iterator
, begin
, end
, cbegin
, cend
and size()
as:
class X
{
public :
typedef std::list<int>::iterator iterator;
typedef std::list<int>::const_iterator const_iterator ;
iterator begin() { return m_container.begin(); }
iterator end() { return m_container.end(); }
const_iterator cbegin() const { return m_container.begin(); }
const_iterator cend() const { return m_container.end(); }
size_t size() const { return m_container.size(); }
private :
std::list<int> m_container;
};
And if you can use C++0x, then use m_container.cbegin()
and m_container.cend()
as:
const_iterator cbegin() const { return m_container.cbegin(); }
const_iterator cend() const { return m_container.cend(); }
A mix of (2) and (3) would probably be what I'd do :
class X {
public :
typedef std::list<int> ElementContainer;
typedef ElementContainer::size_type ElementSizeType;
typedef ElementContainer::iterator ElementIterator;
typedef ElementContainer::const_iterator ConstElementIterator;
ElementIterator elementBegin() { return m_container.begin(); }
ElementIterator elementEnd() { return m_container.end(); }
ConstElementIterator elementBegin() const { return m_container.begin(); }
ConstElementIterator elementEnd() const { return m_container.end(); }
ElementSizeType elementSize() const { return m_container.size(); }
private :
ElementContainer m_container;
};
It still leaves room to write custom iterators (by changing the typedef
s), but as long as the ones provided by the container are ok, they can be used.
2 and 3 really aren't distinct options. However, 3 as written is pretty much useless. No STL algorithm will use CustomIterator::next
. For STL compatibility, you'd write:
// mix of 2 and 3
CustomIterator begin();
CustomIterator end();
and give CustomIterator
the standard operator++
and operator*
I can't think of much cleaner methods; you might consider the lightweight (4) solution giving access with
const Container& container() const { return m_container; }
I would prefer (3) since the container type becomes fully encapsulated, i.e. your type does not necessarily require inclusion of and you can change the container type without recompiling depending modules.