2012-01-24 7 views
1

私は単純なテンプレートクラスを定義しています。このクラスでは、グラフのノードに使用される構造体(struct NodeData)を定義します。最初のコードでは、メソッドのテストでエラーが発生してもコンパイルエラーは発生しません(struct NodeDataには何も呼び出されていなくてもg[nId].anything = "something")。構造体がクラステンプレートの外側または内側に定義されています

問題は、私はMyClassの外で私の構造体の定義とのtypedefを入れている怒鳴る与える第二のコードでは、ここで理解します。この構造体は抽象型T1とT2の2つの変数を格納する必要があるため、struct NodeDataの定義の先頭にtemplate<typename T1, typename T2>を入れました。また、typenameというキーワードをtypedefから削除しました。NodeDataの代わりにNodeData<int, int>を最初のtypedefに入れました(実際にはしたくない場合でも)。expected a type, got 'NodeData'のようないくつかのエラーが表示されます。私がコンパイルすると、次の予想されるエラーが発生します(これは実際には完全に正常です)。'struct NodeData<int, int>' has no member named 'anything'、最初のコードではこのエラーは発生しませんでした。

この2つのコードの違いは何ですか? 2番目のコードでNodeDataを最初のtypedefに指定する必要はありません(struct NodeDataのメンバーvar1とvar2は必ずしもint型ではないため)。または、最初のコードが正常に動作するようにするにはどうしたらいいですか?NodeDataにはanythingという名前のメンバーがないというエラーを検出するにはどうすればよいですか?

まずコード:

#include <iostream> 
#include <boost/graph/adjacency_list.hpp> 

using namespace std; 
using namespace boost; 

template<typename T1, typename T2> 
class MyClass 
{ 
    public: 
     MyClass(); 
     virtual ~MyClass(); 
     void test(T1 p, T2 s); 

    protected: 
     struct NodeData 
     { 
      T1 var1; 
      T2 var2; 
      int var3; 
     }; 

     struct EdgeData 
     { 
      int var; 
     }; 

     typedef adjacency_list<setS, setS, undirectedS, NodeData, EdgeData> Graph; 
     typedef typename Graph::vertex_descriptor NodeDataID; 
     typedef typename Graph::edge_descriptor EdgeDataID; 
     typedef typename graph_traits<Graph>::vertex_iterator VertexIterator; 

     Graph g; 
}; 

template<typename T1, typename T2> 
void MyClass<T1, T2>::test(T1 arg1, T2 arg2) 
{ 
    NodeDataID nId = add_vertex(g); 
    g[nId].anything = "but anything is not in struct NodeData !"; 
    g[nId].var1 = arg1; 
    g[nId].var2 = arg2; 
    g[nId].var3 = 55; 
} 

template<typename T1, typename T2> 
MyClass<T1, T2>::MyClass() 
{ 
    // ... 
} 

template<typename T1, typename T2> 
MyClass<T1, T2>::~MyClass() 
{ 
    // ... 
} 

セカンドコード:

#include <iostream> 
#include <boost/graph/adjacency_list.hpp> 

using namespace std; 
using namespace boost; 

template<typename T1, typename T2> 
struct NodeData 
{ 
    T1 var1; 
    T2 var2; 
    int var3; 
}; 

struct EdgeData 
{ 
    int var; 
}; 

typedef adjacency_list<setS, setS, undirectedS, NodeData<int, int>, EdgeData> Graph; 
typedef Graph::vertex_descriptor NodeDataID; 
typedef Graph::edge_descriptor EdgeDataID; 
typedef graph_traits<Graph>::vertex_iterator VertexIterator; 

template<typename T1, typename T2> 
class MyClass 
{ 
    public: 
     MyClass(); 
     virtual ~MyClass(); 
     void test(T1 p, T2 s); 

    protected: 
     Graph g; 
}; 

template<typename T1, typename T2> 
void MyClass<T1, T2>::test(T1 arg1, T2 arg2) 
{ 
    NodeDataID nId = add_vertex(g); 
    g[nId].anything = "but anything is not in struct NodeData !"; 
    g[nId].var1 = arg1; 
    g[nId].var2 = arg2; 
    g[nId].var3 = 55; 
} 

template<typename T1, typename T2> 
MyClass<T1, T2>::MyClass() 
{ 
    // ... 
} 

template<typename T1, typename T2> 
MyClass<T1, T2>::~MyClass() 
{ 
    // ... 
} 
+1

最初に、void MyClass :: test(T1 arg1、T2 arg2)関数を呼び出しますか?それがインスタンス化されないので、コードにエラーはありません – P3trus

+0

まあ、私はまだそれをインスタンス化していない、私はまだそれのためのコードを書いています。最終的に最初のコードはまったく正しいのですか? – shn

+0

いいえ、それは正しくありませんが、コンパイラはエラーを見ることができません、彼はそれを使用しないためです。 – P3trus

答えて

2

テンプレートのないインスタンス化が存在しない場合は、コンパイルエラーが存在しないので、生成されたコードがありません。このため、通常はテンプレートのインスタンス化を行うテストコードをいくつか用意し、それらを使って愚かな間違いをしないようにすることが重要です。

編集:私が言っていたものを明確にしなかった場合にはは、あなたのコードの一部を使用した例を追加しました。

#include <iostream> 

template<typename T1, typename T2> 
class MyClass 
{ 
public: 
    void Test(T1 p, T2 s); 

protected: 
    struct NodeData 
    { 
     T1 var1; 
     T2 var2; 
     int var3; 
    }; 

private: 
    NodeData m_g; 
}; 

template<typename T1, typename T2> 
void MyClass<T1, T2>::Test(T1 arg1, T2 arg2) 
{ 
    // error C2039: 'anything' is not a member of 'MyClass<T1,T2>::NodeData' 
    m_g.anything = "but anything is not in struct NodeData !"; 
    m_g.var1 = arg1; 
    m_g.var2 = arg2; 
    m_g.var3 = 55; 
} 

int main() { 
    // if you comment out the lines using it the template will never be compiled 
    MyClass<int, double> test; // instantiation of template with T1 = int and T2 = double 
    test.Test(42, 3.14); // calling Test function 

    std::cin.get(); 
    return 0; 
} 
+0

さて、クラスコードがまだ完成していないときに、愚かな間違いを検出するために、この種のテストを進めるには適切かつ適切な方法がありますか? – shn

+0

@ user995434たとえば、テスト駆動開発では、テストを最初に書くことさえできます。このテストでは、コードで何ができるべきかを定義します。そしてテストに合格するまでコードを書いてください。 P3trus @ – P3trus

+0

私は(単なるテストに)以下のようにそれをインスタンス化するトレイた場合、私はコンパイルエラーを取得: MyClassの TST(); tst.test(3,4); // tst.testを使っても(3,4); エラー:「TST」のメンバーに対する要求「テスト」、非クラス型である「MyClassの()」 – shn

関連する問題