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.
精彩评论