I have a problem with compiling llvm. The problem is that my current compiler (clang + libc++) tries to instantiate a template before the template parameter gets defined. Here is the code example:
// ----- TYPEDEFS -----
class NodeEntry;
class EdgeEntry;
typedef std::list<NodeEntry> NodeList;
typedef std::list<EdgeEntry> EdgeList;
typedef NodeList::iterator NodeItr; // line 39
typedef NodeList::const_iterator ConstNodeItr;
typedef EdgeList::iterator EdgeItr;
typedef EdgeList::const_iterator ConstEdgeItr;
typedef std::list<EdgeItr> AdjEdgeList;
typedef AdjEdgeList::iterator AdjEdgeItr;
class NodeEntry {
private:
AdjEdgeList adjEdges;
...
};
class EdgeEntry {
private:
AdjEdgeItr node1AEItr, node2AEItr;
...
};
The error from the compiler is this:
error: field has incomplete type 'PBQP::Graph::NodeEntry'
/Developer/Extras/llvm/include/llvm/CodeGen/PBQP/Graph.h:39:13: note: in instantiation of template class
'std::__1::list<PBQP::Graph::NodeEntry, std::__1::allocator<PBQP::Graph::NodeEntry> >' requested here
typedef NodeList::iterator NodeItr;
^
/Developer/Extras/llvm/include/llvm/CodeGen/PBQP/Graph.h:31:11: note: forward declaration of 'PBQP::Graph::NodeEntry'
class NodeEntry;
As far as I can tell the compiler tries to instantiate std::list<NodeEntry> in order to get the iterator. This fails as NodeEntry is not defined yet. And of course EdgeEntry is using NodeEntry and vice versa.
The obvious question is: How do I fix it?
The educational question is: Why does the compiler try to instantiate the template when defining the type? Should it not wait until we do something with the list?
Thanks.
If you want guaranteed support for incomplete types, your best bet is to create
unique_ptr‘s to them:In the past, many times
std::list<incomplete_type>would just work. However with C++11 andnoexceptspecifications, it is becoming more likely that a complete type is needed, just so that thenoexceptspec can be validated.C++11 guarantees that
unique_ptr<incomplete_type>andshared_ptr<incomplete_type>will work, although there are strict limits. For example wherever~unique_ptr()is executed, the type has to be complete there. But you can usually outline such code to a source and #include the complete type at that point.unique_ptr<incomplete_type>andshared_ptr<incomplete_type>are the only class templates in the C++11 std::lib that are guaranteed to work with incomplete types. Everything else is undefined behavior:[res.on.functions]/p2/b5:
If for some reason the
std::listdoes not need to own the pointer to the incomplete type, thenstd::list<NodeEntry*>would work even better. You might also want to entertain usingvectorinstead oflistsince the cost of moving pointers (or evenunique_ptr‘s) around is relatively small.