3

llvmのコンパイルに問題があります。問題は、現在のコンパイラ(clang + libc ++)が、テンプレートパラメータが定義される前にテンプレートをインスタンス化しようとすることです。コード例は次のとおりです。

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

コンパイラからのエラーは次のとおりです。

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;

私が知る限り、コンパイラーstd::list<NodeEntry>はイテレーターを取得するためにインスタンス化を試みます。NodeEntryがまだ定義されていないため、これは失敗します。そしてもちろん、EdgeEntryはNodeEntryを使用しており、その逆も同様です。

明らかな質問は次のとおりです。どうすれば修正できますか?
教育的な質問は次のとおりです。型を定義するときにコンパイラがテンプレートをインスタンス化しようとするのはなぜですか。リストで何かをするまで待つべきではありませんか?

ありがとう。

4

2 に答える 2

3

不完全なタイプのサポートを保証したい場合、最善の策はunique_ptrそれらに'を作成することです。

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

過去には、多くの場合、std::list<incomplete_type>うまく機能していました。ただし、C ++ 11と仕様では、仕様を検証できるようにするnoexceptために、完全な型が必要になる可能性が高くなっています。noexcept

C ++ 11は、厳密な制限がありますが、それが機能することunique_ptr<incomplete_type>を保証します。shared_ptr<incomplete_type>たとえば~unique_ptr()、実行される場所はどこでも、タイプはそこで完全である必要があります。ただし、通常、そのようなコードの概要をソースに示し、その時点で完全な型を#includeすることができます。

unique_ptr<incomplete_type>shared_ptr<incomplete_type>は、不完全な型での動作が保証されているC ++ 11 std::libの唯一のクラステンプレートです。他のすべては未定義の動作です:

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

特に、次の場合の影響は定義されていません。

..。

  • テンプレートコンポーネントをインスタンス化するときに不完全な型(3.9)がテンプレート引数として使用される場合、そのコンポーネントで特に許可されていない限り。

何らかの理由で、std::listが不完全な型へのポインタを所有する必要がない場合は、std::list<NodeEntry*>さらにうまく機能します。ポインタ(または's)を移動するコストが比較的小さいため、vector代わりにを使用して楽しむこともできます。listunique_ptr

于 2012-07-17T00:55:36.323 に答える
2

すでにリンクされているclangドキュメントによると、libc++のstlコンテナの不完全な型をサポートすることを望んでいません。

これに起因する面白いことは、次のコードがlibc++でコンパイルされないことです。

#include <list>

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

ただし、リストのテンプレートパラメータもテンプレートパラメータに依存するため、このコードは正常にコンパイルされます。

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

後者はより複雑なので、これは奇妙なことに私を驚かせます。

テンプレートの不完全な型に関するISOセクションへの参照も含まれている同様の投稿で、 Boost.Containerは、再帰的なデータ構造を明示的に許可するため、代替として言及されています。同様の問題を診断しているときにこの投稿に出くわしました。これが今のところ私の解決策です。

于 2012-07-16T05:02:34.307 に答える