I am working on generic two-dimensional container with custom iterators.
Now I am trying to have one begin() and one end() function for both my iterator and constant_iterator type.
My custom iterator is inside my template Matrix class (but I put them here separately for the sake of the clarity).
template <class T>
class Matrix {
#pragma mark PUBLIC TYPEDEFS
public:
typedef T value_type;
typedef std::size_t size_type;
//typedef typename T::size_type size_type;
//typedef T::size_type size_type;
#pragma mark -
#pragma mark PRIVATE TYPEDEFS
private:
typedef T* pointer_type;
typedef T** storage_type;
#pragma mark -
#pragma mark PRIVATE VARIABLES
private:
size_type width_;
size_type height_;
storage_type data_;
// private iterators
Iterator<T*, T> m_iterator_;
Iterator<const T*, const T> m_const_iterator_;
H_Iterator<T*, T> m_hiterator_;
H_Iterator<const T*, const T> m_const_hiterator_;
#pragma mark -
#pragma mark PUBLIC VARIABLES & TYPEDEFS
public:
typedef Iterator<T*, T> iterator_type;
typedef Iterator<const T*, const T> const_iterator_type;
typedef H_Iterator<T*, T> hiterator;
typedef H_Iterator<const T*, const T> const_hiterator;
#pragma mark -
#pragma mark CONSTRUCTORS & DESTRUCTORS
public:
explicit Matrix(const std::string& fileName) {
}
Matrix(const size_type& width, const size_type& height) : width_(width),
height_(height),
data_(CreateMatrix(width, height)),
m_iterator_(*data_, width, height),
m_const_iterator_(*data_, width, height),
m_hiterator_(*data_, width, height),
m_const_hiterator_(*data_, width, height),
// fill the created matrix with default values of "T"
for (Matrix<T>::iterator_type it = this->begin(); it != this->end(); ++it)
*it = T();
}
~Matrix() {
delete [] data_[0]; // because in data_[0] is array of value_type
delete [] data_;
}
#pragma mark -
#pragma mark PRIVATE METHODS
private:
storage_type CreateMatrix(const size_type width, const size_type height) {
storage_type d = new pointer_type[height]; // array with pointers pointing to rows inside the "block"
pointer_type block = new value_type[width * height]; // one block of memory to store the data
for (size_type row = 0; row < height; ++row)
d[row] = &block[row * width];
return d;
}
#pragma mark -
#pragma mark PUBLIC METHODS
public:
hiterator h_begin(size_type row) { return m_hiterator_.begin(row); }
hiterator h_end(size_type row) { return m_hiterator_.end(row); }
const_hiterator ch_begin(size_type row) { return m_const_hiterator_.begin(row); }
const_hiterator ch_end(size_type row) { return m_const_hiterator_.end(row); }
And my inner Iterator class + derived H_Iterator class (H_Iterator class is for looping through one row of matrix from left to right)
#pragma mark ITERATOR CLASSES
template <typename P, typename V> // "P" - PointerType; "V" - ValueType
class Iterator : public std::iterator<std::forward_iterator_tag, T> {
protected:
P itData_;
size_type w_; // width of the matrix
size_type h_; // height of the matrix
public:
Iterator(P d, size_type width, size_type height) : itData_(d), w_(width), h_(height) { }
Iterator() { }
public:
V& operator*() const {
return *itData_;
}
Iterator<P, V>& operator++() {
++itData_;
return *this;
}
Iterator<P, V>& operator= (T value) {
*itData_ = value;
return *this;
}
P operator->() {
return itData_;
}
friend bool operator==(const Iterator& lhs, const Iterator& rhs) {
return !(lhs.itData_ != rhs.itData_);
}
friend bool operator!=(const Iterator& lhs, const Iterator& rhs) {
return !(lhs.itData_ == rhs.itData_);
}
Iterator<P, V> begin() { return Iterator<P, V>(itData_, w_, h_); }
Iterator<P, V> end() { return Iterator<P, V>(itData_ + w_ * h_, w_, h_); };
};
template <typename P, typename V> // "P" - PointerType; "V" - ValueType
class H_Iterator : public Iterator<P, V> {
public:
H_Iterator(P d, size_type width, size_type height) : Iterator<P, V>(d, width, height) { }
H_Iterator() { }
public:
H_Iterator<P, V> begin(size_type row) { return H_Iterator<P, V>(this->itData_ + this->w_ * row, this->w_, this->h_); }
H_Iterator<P, V> end(size_type row) { return H_Iterator<P, V>(this->itData_ + this->w_ * row + this->w_, this->w_, this->h_); };
};
Currently if I want to loop through one of the rows using constant iterator I must do it like this (=I must use begin and end function that was made specifically for constant_hiterator - ch_begin() and ch_end()):
Matrix<int> m (5, 5);
for (Matrix<int>::const_hiterator hit = m.ch_begin(row); hit != m.ch_end(row); ++hit) {
cout << *hit << " ";
}
I am struggling to have only one begin() and end() function for both my const_hiterator and hiterator. So I can write iterators code similarly like iterators for std::vector:
std::vector<int> vector;
for (std::vector<int>::const_iterator it = vector.begin(); it != vector.end(); ++it) { }
for (std::vector<int>::iterator it = vector.begin(); it != vector.end(); ++it) { }
I assume that I should have some type of conversion between hiterator and const_hiterator.
There are some heavy head-winds that throw a few monkey wrenches here. Actually, it is common for custom containers to have separate begin() and end() iterators for mutable and constant iterators for one very simple reason, best demonstrated by the following example. This example demonstrates the typical container/iterator semantics that the C++ library implements, and is generally desired for custom container/iterators to implement the same way:
class CustomContainer {
public:
class const_iterator {
// ...
};
class iterator : public const_iterator {
// ...
};
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
};
The standard container/iterator semantics don't use separate begin() and end() methods for mutable and constant iterators. Rather, object.begin(), or pointer->begin() ends up invoking either the constant or the mutable version of begin() depending upon whether object or pointer is a reference/pointer to a mutable or a const instance of the class.
In summary:
1) A mutable iterator begin()/end() methods get called for mutable instances of the class.
2) A begin()/end() on a const instance of a class can only return the constant iterator type. If your begin()/end() operator would return mutable iterators when invoked on a const class instance, then this makes it possible to modify a const instance of the class by simply instantiating its mutable iterators!
3) It is strongly desired for a mutable iterator to be a subclass of the const iterator. This is the easiest way to automatically support passing a mutable iterator to a function or a method that only requires a const iterator parameter (it is also possible to implement that by defining and implementing an overload cast operator, but using subclasses is much easier, and typically results in better performance).
Now, certainly it would be convenient to have a single begin()/end() implementation. And it's not like there's legal requirement that mandates one to always properly support the typical iterator semantics.
But, correctly supporting these expected iterator semantics makes it much easier to leverage all the algorithms in the C++ library, and have them work correctly, with no surprises.
It is certainly possible to declare both mutable and constant begin() and end() methods as wrappers around a private factory that produces a mutable beginning or an ending iterator, with the constant begin()/end() facades degrading it to a constant iterator before returning it. That would be one possible approach. It's not ideal, since the private factory has to be a constant method, in order for it to be invokable from the constant begin()/end() wrappers.
Related
I am trying to implement my own map type and I want an iterator for this map. My understanding is that the value_type of this iterator should be pair<const K, V> (see https://en.cppreference.com/w/cpp/container/map). Now, the iterator's operator* is supposed to return a reference to such a pair. I think this means that I need to store a member in my iterator called current_val so that I can return a reference to it. My question is how to get this to work when V is not copyable. So my implementation looks something like:
template<typename K, typename V>
class Map {
class Iterator {
public:
pair<const K, V>& operator*() { return current_val_; }
Iterator& operator++() {
++index_;
// Now I need to update current_val_;
current_val_ = std::make_pair(keys_[i], vals_[i]);
}
private:
pair<const K, V> current_val_;
int index_ = 0;
K* keys_;
V* vals_;
};
private:
K* keys_;
V* vals_;
};
In this code snippet updating current_val_ doesn't work because it is copying the value into current_val_ but V doesn't support copying.
One possible solution would be to store the data as std::pair<K, V>* instead of storing the keys and values separately, but unfortunately I can't do that.
You should not create a copy. The iterator should provide some means to modify the element in the container, not a copy of that element.
As you are bound to storing the data as K* and V* you cannot simply return a reference to a std::pair<const K,V> because there is no such element to begin with.
You can take a look at std::vector<bool> as an example of container::reference (the type returned from the iterators dereference) not actually being a reference to the element, but some proxy type. This proxy type should be designed to behave like a std::pair<const K,V>&.
Your iterators merely need to store the index into the member arrays, and either a pointer to those arrays or to the whole map. Then you need to use a proxy that implements the methods you want to support:
class Iterator {
public:
proxy operator*() { return *this; }
Iterator& operator++() {
++index_;
return *this;
}
private:
int index_ = 0;
K* keys_;
V* vals_;
};
struct proxy {
K* key;
V* val;
proxy(const Iterator& it) : key(it.keys_+it.index), val(it.vals_+it.index) {}
// make it look like a std::pair<const K,V>
const K& first() { return *key; }
V& second() { return *val; }
// enable assignment of std::pair<const K,V>
proxy& operator=(const std::pair<const K,V>&);
// comparison with std::pair<const K,V>
bool operator==(const std::pair<const K,V>&);
// ... etc ...
};
Not tested, but I hope you get the idea.
I wrote a 'range-class' (get as input start and end index) and output all elements between them (int, char, double etc.)
I have a problem implementing the 'chain-class', chain takes two containers (a range class or a string) and chain it.The problem is that the begin and end class doesn't recognize the inner class type.
Range class implementation:
template<typename T>
struct RangeClass{
T start, last;
RangeClass(T first, T last): start(first), last(last) { };
struct iterator{ //inner class
T it;
T operator* (){ return it;
iterator& operator++() { ++it; return *this; }
bool operator== (const iterator& other){ return it==other.it; }
bool operator!= (const iterator& other){ return it!=other.it; }
}; // end Iterator
iterator end() const{ return iterator{last}
iterator begin() const{ return iterator{start};}
}; // end RangeClass
template<typename T>
RangeClass<T> range(T first, T last){
return RangeClass(first, last);
}
The ChainClass is:
template <typename T, typename V>
struct ChainRanges{
T t1;
V v1;
ChainRanges (const T& first, const V& second):
t1(first), v1(second)
{}
template<typename Y>
struct iterator{
Y var;
Y operator* (){ return var; }
iterator& operator++(){//right? can access outer class fields?
if(var==*it.end())
var=*v1.begin();
else
++var;
bool operator== (const iterator& other){ return var==other.var; }
bool operator!= (const oiterator& other){ return var!=other.var; }
}; // end Iterator
auto end() const {
//auto? or iterator<Y>
auto var = ( *(v1.end()) ) ;
return iterator{var};
}
auto begin() const{
auto var = ( *(t1.begin()) ) ;
return iterator{var};
}
}; // end struct chain
template<typename T, typename V>
ChainRanges<T,V >
chain(T first, V second)
{
return ChainRanges(first, second);
}
Main is :
for (int i: range(5,9))
cout << i; //prints 5678
for (char i: chain(range('a','e'), string("hello")))
cout << i;//want this to work = // abcdhello
No you cannot access outer class fields. Subclasses have friend-style access, but no state access, to their outer class. Of you want a pointer to their outer class you have to add one.
Values have fixed types in C++. You cannot have an.iterator value of two.possible types.
You can have a pointer to two possible types if they share a basr class. You can use type erasure to wrap multiple types into one variable. You can use std variant, std any, void pointers and careful manual vtables, concept and model templates wrapped by regular type abstractions, or a myriad of other ways to have "values.of more than one type"; they aren't really values of more than one type, just polymorphic behaviour values that include some type aware dispatching code.
Templates are not inheritly runtime polymorphic in C++, unlike Generics in Java/C#. Templates generate types and functions. The generated types and functions are unrelated at runtime, unless of course you make them related.
There are piles of ways to solve your problem, from boost any iterator to fun type manual type erasing the concept of iterable and printable, or print-iterable even. I know of none that you'd be wise to try at your level of C++ expertise.
General context:
I am trying to build a container that will behave as as wrapper around a multi-dimensional array of run time defined dimensions - in fact the underlying array is of course a 1D array of the total size. The main part is that operator [] returns a wrapper on the sub array.
As containers need iterators, I am currently implementing iterators on that container, both Container::iterator and Container::const_iterator. I try hard to mimic standard container iterators, and they should respect all the requirements for random access and output iterators.
I have already noted the following requirements:
a public default constructor
(of course copy and move semantics)
implicit conversion from an iterator to a const_iterator
iterator and const_interator should be comparable
Specific context:
Standard containers iterators provide no conversion at all from a const_iterator to an iterator, because removing constness can be dangerous. I have already searched SO for that problem and found How to remove constness of const_iterator? where answers propose differents tricks to remove constness from an operator. So I now wonder whether I should implement an explicit conversion from a const_iterator to an iterator ala const_cast on pointers.
Question:
What are the risks in implementing an explicit conversion from a const_iterator to a (non const) iterator and how is it different from the solutions from the linked question (copied here for easier reading):
using advance and distance (constant time form my random access iterators)
iter i(d.begin());
advance (i,distance<ConstIter>(i,ci));
using erase:
template <typename Container, typename ConstIterator>
typename Container::iterator remove_constness(Container& c, ConstIterator it)
{
return c.erase(it, it);
}
For references, here is a simplified and partial implementation of my iterators:
// Base for both iterator and const_iterator to ease comparisons
template <class T>
class BaseIterator {
protected:
T *elt; // high simplification here...
BaseIterator(T* elt): elt(elt) {}
virtual ~BaseIterator() {}
public:
bool operator == (const BaseIterator& other) {
return elt == other.elt;
}
bool operator != (const BaseIterator& other) {
return ! operator == (other);
}
// other comparisons omitted...
BaseIterator& add(int n) {
elt += n;
return *this;
}
};
// Iterators<T> in non const iterator, Iterator<T, 1> is const_iterator
template <class T, int cnst=0, class U= typename std::conditional<cnst, const T, T>::type >
class Iterator: public BaseIterator<T> {
using BaseIterator<T>::elt;
public:
using value_type = U;
using reference = U*;
using pointer = U&;
using difference_type = int;
using iterator_category = std::random_access_iterator_tag;
Iterator(): BaseIterator<T>(nullptr);
Iterator(T* elt): BaseIterator<T>(elt) {}
// conversion from iterator to const_iterator
template <class X, typename = typename std::enable_if<
(cnst == 1) && std::is_same<X, T>::value>::type>
Iterator(const BaseIterator<X>& other): BaseIterator<X>(other) {};
// HERE: explicit conversion from const_iterator to non const
template <class X, typename = typename std::enable_if<
std::is_same<X, T>::value && (cnst == 0)>::type>
explicit Iterator(const Iterator<X, 1 - cnst>& other): BaseIterator<T>(other) {}
// partial implementation below
U& operator *() {
return *elt;
}
U* operator ->() {
return elt;
}
Iterator<T, cnst, U>& operator ++() {
this->add(1);
return *this;
}
};
Both the methods you quote require non-const access to the container, so you can't get access to const underlying elements as non-const.
What you are suggesting doesn't, so it can be UB [dcl.type.cv]
I have an STL container whose element type is const std::shared_ptr<MyClass>.
I want to supply two iterator types to the user:
MyContainer::iterator
typedefed as std::vector<const std::shared_ptr<MyClass>>::iterator
(which should be the same type as std::vector<const std::shared_ptr<const MyClass>>::const_iterator
MyContainer::const_iterator
typedefed as std::vector<const std::shared_ptr<const MyClass>>::iterator
(which should be the same type as std::vector<const std::shared_ptr<const MyClass>>::const_iterator
In other words, I want the "const" to refer to the MyClass constness, not shared_ptr constness. The solution I found for getting the second iterator type is getting the first one, which is easy (e.g. using vector::begin), and then converting it to the second type using static_cast (fixme: no need to use const_cast because I'm adding constness, not removing it).
Would that be the common good-design way to achieve that, or there's a better/more common way?
typedefed as std::vector<const std::shared_ptr<MyClass>>::iterator (which should be the same type as std::vector<std::shared_ptr<const MyClass>>::const_iterator
But it probably isn't the same type. Iterators are not just pointers. If the iterator and const_iterator types are defined inside vector then they are completely unrelated types:
template<typename T>
class vector
{
class iterator;
class const_iterator;
// ...
vector<const int> is a different type to vector<int> and so their nested types are also different. As far as the compiler is concerned they are completely unrelated types, i.e. you cannot just move const around to any point in this type and get compatible types:
vector<const shared_ptr<const T>>::iterator
You cannot use const_cast to convert between unrelated types. You can use static_cast to convert a vector<T>::iterator to a vector<T>::const_iterator but it's not really a cast, you're constructing the latter from the former, which is allowed because that conversion is required by the standard.
You can convert a shared_ptr<const T> to a shared_ptr<T> with const_pointer_cast<T> but again only because it's defined to work by the standard, not because the types are inherently compatible and not because it "just works" like plain ol' pointers.
Since vector's iterators don't provide the deep-constness you want, you'll need to write your own, but it's not hard:
class MyClass { };
class MyContainer
{
typedef std::vector<std::shared_ptr<MyClass>> container_type;
container_type m_cont;
public:
typedef container_type::iterator iterator;
class const_iterator
{
typedef container_type::const_iterator internal_iterator;
typedef std::iterator_traits<internal_iterator> internal_traits;
const_iterator(internal_iterator i) : m_internal(i) { }
friend class MyContainer;
public:
const_iterator() { }
const_iterator(iterator i) : m_internal(i) { }
typedef std::shared_ptr<const MyClass> value_type;
typedef const value_type& reference;
typedef const value_type* pointer;
typedef internal_traits::difference_type difference_type;
typedef internal_traits::iterator_category iterator_category;
const_iterator& operator++() { ++m_internal; return *this; }
const_iterator operator++(int) { const_iterator tmp = *this; ++m_internal; return tmp; }
reference operator*() const { m_value = *m_internal; return m_value; }
pointer operator->() const { m_value = *m_internal; return &m_value; }
// ...
private:
internal_iterator m_internal;
mutable value_type m_value;
};
iterator begin() { return m_cont.begin(); }
const_iterator begin() const { return const_iterator(m_cont.begin()); }
// ...
};
That iterator type is mising a few things (operator--, operator+) but they're easy to add, following the same ideas as already shown.
The key point to notice is that in order for const_iterator::operator* to return a reference, there needs to be a shared_ptr<const MyClass> object stored as a member of the iterator. That member acts as a "cache" for the shared_ptr<const MyClass> value, because the underlying container's real elements are a different type, shared_ptr<MyClass>, so you need somewhere to cache the converted value so a reference to it can be returned. N.B. Doing this slightly breaks the iterator requirements, because the following doesn't work as expected:
MyContainer::const_iterator ci = c.begin();
const shared_ptr<const MyClass>& ref = *ci;
const MyClass* ptr = ref.get();
++ci;
(void) *ci;
assert( ptr == ref.get() ); // FAIL!
The reason the assertion fails is that *ci doesn't return a reference to an underlying element of the container, but to a member of the iterator, which gets modified by the following increment and dereference. If this behaviour isn't acceptable you'll need to return a proxy from your iterator instead of caching a value. Or return a shared_ptr<const MyClass> when the const_iterator is dereferenced. (The difficulties of getting this 100% right is one of the reasons STL containers don't try to model deep constness!)
A lot of the effort of defining your own iterator types is done for you by the boost::iterator_adaptor utility, so the example above is only really useful for exposition. With that adaptor you'd only need to do this to get your own custom iterator types with the desired behaviour:
struct iterator
: boost::iterator_adaptor<iterator, container_type::iterator>
{
iterator() { }
iterator(container_type::iterator i) : iterator_adaptor(i) { }
};
struct const_iterator
: boost::iterator_adaptor<const_iterator, container_type::const_iterator, std::shared_ptr<const MyClass>, boost::use_default, std::shared_ptr<const MyClass>>
{
const_iterator() { }
const_iterator(iterator i) : iterator_adaptor(i.base()) { }
const_iterator(container_type::const_iterator i) : iterator_adaptor(i) { }
};
boost::iterator_adaptor makes it pretty easy to define your own iterator types based on another iterator type. So you can set it up so that *iter is a const shared_ptr<MyClass>& or const shared_ptr<const MyClass>& as desired.
Though in the const_iterator case, dereferencing can't return a const shared_ptr<const MyClass>& if what you actually have is shared_ptr<MyClass>. So we'll define const_iterator::reference as just shared_ptr<const MyClass> and return by value.
#include <boost/iterator/iterator_adaptor.hpp>
class MyContainer {
public:
class iterator;
class const_iterator;
class iterator :
public boost::iterator_adaptor<
iterator, // This class, for CRTP
std::vector<const std::shared_ptr<MyClass>>::const_iterator,
// Base type
const std::shared_ptr<MyClass> > // value_type
{
public:
iterator() {}
iterator(const iterator&) = default;
private:
friend class MyContainer; // allow private constructor
friend class boost::iterator_core_access; // allow dereference()
explicit iterator(base_type iter) : iterator_adaptor(iter) {}
const std::shared_ptr<MyClass>& dereference() const
{ return *base_reference(); }
};
class const_iterator :
public boost::iterator_adaptor<
const_iterator, // This class, for CRTP
std::vector<const std::shared_ptr<MyClass>>::const_iterator,
// Base type
const std::shared_ptr<const MyClass>, // value_type
boost::use_default, // difference_type
std::shared_ptr<const MyClass> > // reference_type
{
public:
const_iterator();
const_iterator(const const_iterator&) = default;
// Implicit conversion from iterator to const_iterator:
const_iterator(const iterator& iter) : iterator_adaptor(iter.base()) {}
private:
friend class MyContainer; // allow private constructor
friend class boost::iterator_core_access; // allow dereference()
explicit const_iterator(base_type iter) : iterator_adaptor(iter) {}
std::shared_ptr<const MyClass> dereference() const
{ return *base_reference(); }
};
iterator begin() { return iterator(mVec.begin()); }
iterator end() { return iterator(mVec.end()); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
const_iterator cbegin() const { return const_iterator(mVec.begin()); }
const_iterator cend() const { return const_iterator(mVec.end()); }
private:
std::vector<const std::shared_ptr<MyClass>> mVec;
};
shared_ptr and other standard smart pointers are not designed with deep-constness in mind. They are trying to be as close to raw pointer usage as possible, and raw pointer's const-ness does not affect the pointee's const-ness.
Andrei Alexandrescu's Loki::SmartPtr (described in his Modern C++ Design) implements reference counting and deep const-ness as policies, which would give you the effect you're looking for. If you don't mind switching to a non-standard smart pointer in order to get non-standard behavior, that may be one way to go.
Hi can anyone tell me why VS2010 gives me an error with this code, I can't see what's the problem with it?
Error code : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::vector<_Ty>' (or there is no acceptable conversion)
// Elements container
typedef std::vector<CFVFElementPtr> ElementArray;
typedef std::map<CVertexSemantic::Type, ElementArray> ElementsMap;
// Create an empty array of elements
ElementsMap::value_type::second_type allElements;
// Concatinate each std::vector found within the map
std::transform(m_elementsMap.begin(), m_elementsMap.end(),
std::insert_iterator<ElementArray>(allElements, allElements.end()),
select2nd<ElementsMap::value_type>() );
All I am trying to do is this
for (auto i = m_elementsMap.begin(); i != m_elementsMap.end(); ++i)
{
const ElementArray& elements = (*i).second;
allElements.insert(allElements.end(), elements.begin(), elements.end());
}
As a response to Pablo, I tried creating a custom iterator that accepts an array of ElementArray, but I'm now getting a bucket load of errors.
template < class Container >
class container_insert_interator
{
public:
typedef container_insert_interator<Container> this_type;
typedef Container container_type;
typedef typename Container::const_reference const_reference;
typedef typename Container::value_type valty;
explicit container_insert_interator (Container& cont, typename Container::iterator iter)
: container(&cont), iter(iter)
{ }
this_type& operator = (typename const_reference value)
{
iter = container->insert( iter, std::begin(value), std::end(value) );
++iter;
return *this;
}
this_type& operator* ()
{
return *this;
}
this_type& operator++ ()
{
return *this;
}
this_type operator++ (int)
{
return *this;
}
protected:
Container* container; // pointer to container
typename Container::iterator iter ; // iterator into container
};
The problem is ElementsMap::value_type::second_type is ElementArray. That is, you're trying to insert instances of ElementArray into an ElementArray, which really holds instances of CFVFElementPtr.
Update: Changing your declaration of operator= from
this_type& operator = (typename const_reference value)
to
template<typename OtherContainer>
this_type& operator = ( OtherContainer const& value)
almost works. Except that neither VS 2010 or GCC 4.6.1 provide the vector::insert overload that returns an iterator. You'll probably need a newer compiler if you want your ranged insert to return an iterator to replace iter.
Changing the implementation to always insert at the end, namely
container->insert( container->end(), std::begin(value), std::end(value) );
in operator= compiles fine with GCC 4.6.1 (and, of course, you can remove all references to iter in your iterator class).
You might consider using a functor that can append elements to your target array along with std::for_each to walk the map:
struct ElementArray_appender
{
ElementArray_appender( ElementArray& dest_) : dest(dest_) {
};
void operator()( ElementsMap::value_type const& map_item) {
ElementArray const& vec( map_item.second);
dest.insert( dest.end(), vec.begin(), vec.end());
};
private:
ElementArray& dest;
};
// in whatever function:
std::for_each( m_elementsMap.begin(), m_elementsMap.end(), ElementArray_appender(allElements));
I found the answer, the poblem was with my custom iterator. The correct one that works is
template < class Container >
class container_back_insert_interator
{
public:
typedef container_back_insert_interator<Container> this_type;
typedef Container container_type;
typedef typename container_type::const_reference const_reference;
typedef typename container_type::value_type valty;
explicit container_back_insert_interator (container_type& cont)
: container(&cont)
{ }
this_type& operator = (const_reference value)
{
container->insert( container->end(), std::begin(value), std::end(value) );
return *this;
}
this_type& operator* ()
{
return *this;
}
this_type& operator++ ()
{
return *this;
}
this_type operator++ (int)
{
return *this;
}
protected:
container_type* container; // pointer to container
};
template < class Container >
inline container_back_insert_interator<Container> container_back_inserter(Container& cont)
{
return container_back_insert_interator<Container>(cont);
}
However, I must warn that if you do use this in Visual Studio 2010 you will have to implement an SGI form of std::transform. The version that ships with VS2010 for some reason throws numerous errors, all of which lie within the <xutility> header.
This std::transform works just fine.