2012-01-24 48 views
1

我有一個定義了簡單的模板類。在這個類中,我定義了一個用於圖的節點的結構(struct NodeData)。對於我給出的第一個代碼,沒有編譯錯誤,即使我在方法測試中做了一個錯誤(我做了g[nId].anything = "something",即使struct NodeData沒有一個叫做任何變量的變量)。在類模板外部或內部定義的結構體

爲了理解問題出在哪裏,在第二個代碼中,我給出了下面的代碼,我把我的結構體定義和typedef放在了MyClass之外。我已經把template<typename T1, typename T2>置於struct NodeData的定義之上,因爲這個結構需要存儲2個抽象類型T1和T2的變量。我還從typedefs中刪除了關鍵字typename,並且我在第一個typedef中放入了NodeData<int, int>而不是NodeData(即使我實際上不想這樣做),否則它會在此行中提供一些錯誤,如:expected a type, got 'NodeData'。當我編譯時,它會給出以下預期錯誤(實際上完全正常):'struct NodeData<int, int>' has no member named 'anything',而對於第一個代碼,我沒有得到這個錯誤!

這兩個代碼有什麼區別?我該如何做第二個代碼,不必爲第一個typedef指定NodeData(因爲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

+0

@ P3trus如果我的托盤將其實例化爲以下內容(僅用於測試),我收到編譯錯誤: MyClass tst(); tst.test(3,4); //或甚至用tst.test (3,4); 錯誤:請求'tst'中的成員'test',它是非類類型'MyClass ()' – shn

相關問題