开发者

Missing Template Arguments

This is part of a homework assignment, but I've reduced the problem as far as possible. The code presented doesn't really do anything, just create some objects, so I am down to pure language issues.

I think my question is: Is it possible for a template class to create another class of the same template type?

The assignment is to have a main.cc as following:

#include "linkedlist.hh"

int main()
{
    LinkedList<int> aList;
    ListIterator elements = aList.iterator(); // if commented out, then no error
}

I have the following for linkedlist.hh:

template <typename T> class LinkedList;
template <typename T> class ListIterator;

template <typename T>
    class LinkedList {
    public:
    ListIterator<T> iterator();
};

template <typename T>
    ListIterator<T> LinkedList<T>::iterator() {
    return new ListIterator<T>;
}

template <typename T>
    class ListIterator {
};

Which give the following error with g++-4.6:

main.cc: In function ‘int main()’:
main.cc:6:18: error: missing template arguments before ‘elements’
main.cc:6:18: error: expected ‘;’ before ‘elements’

And a similar error with clang++-2.9:

main.cc:6:5: error: cannot refer to class template 'ListIterator' without a
      template argument list
    ListIterator elements = list.iterator();
    ^
In file inc开发者_JAVA百科luded from main.cc:1:
./linkedlist.hh:16:11: note: template is declared here
    class ListIterator {

UPDATE: Yes if I could change main.cc, then I could do the following, but I don't think that is what the assignment is.

main.cc

#include "linkedlist.hh"

int main()
{
    LinkedList<int> aList;
    ListIterator<int> elements = aList.iterator();
}

and linkedlist.hh

template <typename T> class LinkedList;
template <typename T> class ListIterator;

template <typename T>
    class LinkedList {
    public:
    ListIterator<T> iterator();
};

template <typename T>
    ListIterator<T> LinkedList<T>::iterator() {
    ListIterator<T> anIterator;
    return anIterator;
}

template <typename T>
    class ListIterator {
};


Shouldn't that be ListIterator<int>?


ListIterator is a template, obviously you have to give it a template parameter. Try ListIterator<int>


This is how you could implement a generic iterator that could do some basic operations on the iterator for a list of any type of elements, but it would be unusual.

struct ListIteratorBase {
  virtual void advance() = 0;
  virtual bool atEnd() const = 0;
  virtual ~ListIteratorBase() { }
};

template <typename T>
struct BasicListIterator : ListIteratorBase {
  virtual void advance(); // implement this
  virtual bool atEnd() const;  // and this
  T value() const; // and this
};

struct ListIterator {
  template <typename T> ListIterator(BasicListIterator<T> &iter)
  : iter_ptr(new BasicListIterator<T>(iter))
  {
  }

  ~ListIterator() { delete iter_ptr; }

  void operator++() { iter_ptr->advance(); }
  bool atEnd() const { return iter_ptr->atEnd(); }

  // Method to get the value for a particular type.  It is up to the caller to
  // make sure the type is right at runtime.
  template <typename T>
  T get<>() const
  {
    BasicListIterator<T> *p = dynamic_cast<BasicListIterator<T> *>(iter_ptr);
    assert(p);
    return p->value();
  }

  ~ListIterator() { delete iter_ptr; }

  ListIteratorBase *iter_ptr;
};

You would then need

template <typename T>
BasicListIterator<T> LinkedList<T>::iterator() { ... }


For that purpose, in C++11, auto directive was added

see Type inference


Rename ListIterator and add typedef MyListIterator<int> ListIterator; to the end of the header. Then the main code will work unmodified.

This is just a trick to make this particular given code work. You can't make a standard library compliant iterator that is not a template or template-dependent. If you don't have to make a standard library compliant iterator, then you can employ a technique called type erasure (Vaughn Cato's answer), but that's a rather advanced topic.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜