2012-04-08 4 views
3

Ich habe ein Problem mit der Kompilierung llvm. Das Problem ist, dass mein aktueller Compiler (clang + libC++) versucht, eine Vorlage zu instanziieren, bevor der Template-Parameter definiert wird. Hier ist der Code Beispiel:Instantiierung einer Liste mit einem unvollständigen Typ in einem typedef

// ----- 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; 
    ... 
}; 

Der Fehler vom Compiler ist dies:

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; 

Soweit ich die Compiler sagen kann, versucht std::list<NodeEntry> um zu instanziiert den Iterator zu bekommen. Dies schlägt fehl, da NodeEntry noch nicht definiert ist. Und natürlich verwendet EdgeEntry NodeEntry und umgekehrt.

Die offensichtliche Frage ist: Wie repariere ich es?
Die pädagogische Frage ist: Warum versucht der Compiler die Vorlage bei der Definition des Typs zu instanziieren? Sollte es nicht warten, bis wir etwas mit der Liste machen?

Danke.

+1

Es scheint mit compl ++ 3.0 und libC++ (svn Version 154095) auf Linux zu kompilieren. – alexisdm

+0

Interessant. Laut clang Webseite [wird die Funktion nicht unterstützt] (http://clang.llvm.org/compatibility.html#undep_incomplete) –

Antwort

3

Wenn Sie unvollständige Arten garantierter Unterstützung wollen, ist Ihre beste Wette unique_ptr ‚s ihnen zu schaffen:

typedef std::list<std::unique_ptr<NodeEntry>> NodeList; 
typedef std::list<std::unique_ptr<EdgeEntry>> EdgeList; 

In der Vergangenheit std::list<incomplete_type> viele Male würde nur funktionieren. Mit den Spezifikationen C++ 11 und noexcept wird es jedoch wahrscheinlicher, dass ein vollständiger Typ benötigt wird, nur so dass die noexcept Spezifikation validiert werden kann.

C++ 11 garantiert, dass unique_ptr<incomplete_type> und shared_ptr<incomplete_type> funktionieren, obwohl es strenge Grenzen gibt. Zum Beispiel wo immer ~unique_ptr() ausgeführt wird, muss der Typ dort vollständig sein. Aber Sie können solchen Code normalerweise zu einer Quelle umreißen und den vollständigen Typ an dieser Stelle einschließen.

unique_ptr<incomplete_type> und shared_ptr<incomplete_type> sind die einzigen Klassenvorlagen in C++ 11 std :: lib, die garantiert mit unvollständigen Typen arbeiten. Alles andere ist undefiniertes Verhalten:

[res.on.Funktionen]/p2/b5:

Insbesondere werden die Wirkungen in den folgenden Fällen nicht definiert:

...

  • wenn ein unvollständiger Typ (3.9) als Vorlage verwendet wird, Argument beim Instanziieren einer Schablonenkomponente, sofern nicht ausdrücklich für diese Komponente zulässig.

Wenn aus irgendeinem Grund die std::list nicht den Zeiger auf den unvollständigen Typ besitzen müssen, dann wäre std::list<NodeEntry*> arbeiten noch besser. Vielleicht möchten Sie auch mit vector anstelle von list unterhalten, da die Kosten für das Verschieben von Zeigern (oder sogar unique_ptr) relativ gering ist.

2

Nach der clang docs auch bereits verknüpft, sind sie nicht bereit, unvollständige Typen für STL-Container in libC++ zu unterstützen.

Etwas komisch, die aus dieser stammt der folgende Code wird mit libc nicht kompilieren ++:

#include <list> 

struct Tree { 
    // ... more stuff ... 
    std::list<Tree> mChildren; 
}; 

aber dieser Code kompiliert gut, weil auch Template-Parameter in der Liste auf einem Template-Parameter abhängig:

template<typename T> 
struct TreeT { 
    // ... more stuff ... 
private: 
    std::list<TreeT<T> > mChildren; 
}; 

Das erscheint mir merkwürdig, da letzteres komplexer ist.

Auf einer ähnlichen post, die auch einen Verweis auf den ISO-Abschnitt über unvollständige Typen in Vorlagen enthält, wird Boost.Container als eine Alternative erwähnt, da explizit rekursive Datenstrukturen ermöglicht werden. Ich stieß auf diesen Beitrag, als ich ein ähnliches Problem diagnostizierte, und das ist meine Lösung für den Moment.

Verwandte Themen