views:

79

answers:

4

Hi everoby, I have the following design in one of my projects:

template<typename C> class B {
    int numValue;
    C inner;
}

template<typename C> class A {
    vector<B<C>> container;
    ...
    Iterator InsertItem(C item) {...}
}

What I want is a way to modify the existing vector iterator to return an Iterator which will return &inner on dereferencing instead of returning a reference to a B object. Hope it doesn't need a complete iterator class implementation.

A: 

If your iterator returns &inner, how will you ever access numValue?

If you create your own A::iterator, it should be easy to have it contain a vector<B<C>>::iterator and forward most operations through it. Yes you'll need a full iterator class implementation, but it won't be difficult at all.

Mark Ransom
I think I'll write my own iterator type with an embedded vector<B<C>>::iterator as you suggest, but I can't find a good tutorial on writing custom iterator; should I make it inherits from std::iterator ?
fokenrute
@user456668: Yes, you should inherit from `std::iterator`, though this just provides some typedefs and makes `iterator_traits` available for the type. Otherwise you'll just have to overload all operators that `vector::iterator` does (forward to the underlying iterator) and do the special things in operators `*`, `->` and `[]`.
UncleBens
+1  A: 

I don't see where you need to modify an iterator at all. Rather, you just need to add a few member functions to B that return appropriate iterators to inner:

template <class C>
class B { 
    C inner;
public:

    typedef typename C::iterator iterator;
    typedef typename C::const_iterator const_iterator;
    // etc.

    iterator begin() { return inner.begin(); }
    iterator end()   { return inner.end(); }

    // and so on for rbegin, rend, cbegin, cend, ...
};

Edit: I should add that if you want to support (for one example) back_insert_iterator, you'll also need to add a push_back to B, which you'll also (probably) implement by having it forward to C::push_back.

Jerry Coffin
Where does the question say or imply that `C` is a container class?
Mark Ransom
@Mark: An iterator implies iteration. Since B isn't a container class, for iteration to make much sense, C just about needs to be. If C isn't at least vaguely container-like, what will the iterator iterate over? Granted, C could be an array (for example), in which case you'd need to do more of the work yourself, but absent a specific statement to the contrary, I'd assume he's sensible enough to avoid using raw arrays.
Jerry Coffin
`A` contains a vector, I assumed that was what needed to be iterated.
Mark Ransom
If that's what he's after, he's basically got things "inside out" -- what he needs has little to do with iterators at all, but a way to make B act as a proxy for C (which is fairly simple, but *completely* different).
Jerry Coffin
+2  A: 

Such an iterator is Boost.TransformIterator

Example (filling in your code, not that it is particularly good design).

#include <vector>
#include <iostream>
#include <functional>
#include <boost/iterator/transform_iterator.hpp>
using namespace std;

template<typename C> struct B {
    int numValue;
    C inner;
};

template <class T>
struct get_inner: std::unary_function<B<T>&, T&>
{
    T& operator()(B<T>& value) const { return value.inner; }
};

template<typename C> struct A {
    vector<B<C> > container;
    typedef boost::transform_iterator<get_inner<C>, typename vector<B<C> >::iterator> Iterator;
    Iterator InsertItem(C item) {
        B<C> b = {0, item};
        container.push_back(b);
        return Iterator(--container.end());
    }
};

int main()
{
    A<double> a;
    A<double>::Iterator it = a.InsertItem(3.14);
    std::cout << *it << '\n';
}
UncleBens
+1 You beat me to it.
sellibitze
Indeed, this seems the less painful solution, but I don't like the idea of introducing some boost depedencies in my project.
fokenrute
A: 

Use boost::transform_iterator to create a new iterator that wraps your vector iterator, but yields the inner value instead:

template<typename C>
C& getInner(B<C>& b)
{
    return b.inner;
}    

vector<B<C>> container;
typedef boost::transform_iterator<C&(*)(B<C>&), vector<B<C> >::iterator> inner_iterator;
inner_iterator it=boost::make_transform_iterator(container.begin(), getInner<C>)
Anthony Williams