1

I am designing my own iterator class so that I can create custom iterators for my containers. I figured this was the simplest approach, rather than inheriting from bidirectional_iterator or iterator_traits. The problem is that the containers are also templated. When writing my copy constructor and assignment operators for this class, the compiler does not like the return type nor the parameter (which is an

iterator<someContainer<someClasstype>>.

Is this a problem that can be fixed? Or is this a limitation of how deep templates can go?

Here is the class:

template <template<class Data> class Cont, class T>
class iterator
{
    typedef typename Cont<T>    container_type;
    typedef T*      ptr_type;
    typedef T       value_type;
private:
    ptr_type _ptr;
    size_t _alloc;  // offset to apply when jumping contiguos addresses
public:
    // ctors

    // Default
    explicit iterator()
    {
        _ptr = 0;
        _alloc = sizeof(value_type);
    }

    // reference
    explicit iterator(const value_type& address): _ptr(address)
    {
            _alloc = sizeof(value_type);
    }

    // pointer
    explicit iterator(const ptr_type ptr): _ptr(ptr)
    {
        _alloc = sizeof(value_type);
    }

    // copy
    iterator(const iterator<Cont<T>, T>& right)
    {
        _ptr = right._ptr;
        _alloc = right._alloc;
    }


    // operators

    // assignment
    iterator<Cont<T>, T>& operator=(const value_type& address)
    {
        return *this(address);
    }

    iterator<Cont<T>, T>& operator=(const ptr_type ptr)
    {
        return *this(ptr);
    }

    iterator<Cont<T>, T>& operator=(const iterator<container_type, T>& right)
    {
        return *this(right);
    }

    // equality
    bool operator==(const iterator<container_type, T>& right)
    {
        return (_ptr == right._ptr && _alloc == right._alloc);
    }

    // dereference
    T& operator*(const iterator<container_type, T>& it)
    {
        return *_ptr;
    }

    T* operator()   // get value operator? (ie list<int>::iterator returns the memory address, even though its a class
    {
        return _ptr;
    }

};

I have so far tried these combinations:

iterator<Cont<T>>
iterator<Cont<T>, T>
iterator<container_type> // typedef of Cont<T>
iterator<container_type, T> 

but none of them are accepted. Compiler errors are:

Error   1   error C3200: 'Cont<T>' : invalid template argument for template parameter 'Cont', expected a class template c:\users\sapphire\documents\visual studio 2012\projects\hybridlist\hybridlist\iterator.h    43

Error   2   error C2976: 'iterator' : too few template arguments    c:\users\sapphire\documents\visual studio 2012\projects\hybridlist\hybridlist\iterator.h    53
Igneous01
  • 719
  • 1
  • 10
  • 24
  • 2
    Well, the error message is pretty clear. It should be `iterator`, not `iterator, T>`. You've outsmarted yourself with overly templated template template templates. It happens... – Kerrek SB Feb 23 '13 at 11:40
  • Line 4 you don't want `typename`: http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords. Your `operator()` is missing a second `()` too. – Flexo Feb 23 '13 at 11:41
  • 2
    By the way, template template arguments are generally not that useful, because they are very restrictive. The usual approach is to template on the full *type*, and use traits to extract parametric information. – Kerrek SB Feb 23 '13 at 11:41
  • 1
    "I figured this was the simplest approach" -- you figured wrong. Also, you need to neither inherit from any iterator category or `std::iterator_traits`- `std::iterator` is what you want to inherit from. Or even better, [`boost::iterator_facade`](http://www.boost.org/libs/iterator/doc/iterator_facade.html). Guess why that thing exists - because even advanced users have it hard to actually implement correct iterators. – Xeo Feb 23 '13 at 11:42
  • @Flexo the operator() was an assumption I was making about how to return a specific member value. For example if you set a list iterator to list.begin, you can cout the address that iterator points to, by just passing in the object. Although this may be in fact due to << operator. – Igneous01 Feb 23 '13 at 11:48
  • @David You can print out a `std::list::iterator`? That probably means your implementation uses raw pointers for `std::list` iterators. – Joseph Mansfield Feb 23 '13 at 11:52
  • @sftrabbit my mistake, turns out you cant (which makes sense). Im not sure why I thought this was possible. I think I might have confused the iterator with a pointer... – Igneous01 Feb 23 '13 at 11:59

1 Answers1

4

iterator's first template parameter is a template template parameter. That is, it should take a template as its argument. You can't give Cont<T> because that is a specific instantiation of a template. Try:

iterator<Cont, T>

It's worth noting that Data in template<class Data> class Cont is redundant. Just template<class> class Cont will do fine.

Consider inheriting from std::iterator - this is what it's designed for.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • Bahh, I didn't realize that a template template parameter didnt need to be specified with template parameters again. This solved the issue. – Igneous01 Feb 23 '13 at 11:51