2012-04-08 96 views
0

內部定義的C++類我有下面的代碼,編譯器錯誤是: 爲什麼不能graph_algorithm找到圖形類的內部頂點類?類找不到內模板

graph_algorithms.h:26:33: error: ‘Graph::graph<T>::vertex’ is not a type 
graph_algorithms.h:26:55: error: ‘Graph::graph<T>::vertex’ is not a type 
graph_algorithms.h: In member function ‘bool Graph::graph_algorithm<T>::vertex_comparer::operator()(int&, int&)’: 
graph_algorithms.h:28:10: error: ‘t1’ was not declared in this scope 
graph_algorithms.h:28:21: error: ‘t2’ was not declared in this scope 
graph_algorithms.h:28:33: error: expected primary-expression before ‘return’ 
graph_algorithms.h:28:33: error: expected ‘:’ before ‘return’ 
graph_algorithms.h:28:33: error: expected primary-expression before ‘return’ 
graph_algorithms.h:28:33: error: expected ‘;’ before ‘return’ 
graph_algorithms.h:29:7: warning: no return statement in function returning non-void [-Wreturn-type] 

#ifndef GRAPH_H_ 
#define GRAPH_H_ 

#include <list> 
#include <algorithm> 
#include <vector> 
#include <utility> 
#include <iostream> 
#include <stdexcept> 
#include <assert.h> 

namespace Graph 
{ 
    template <class T> 
    class graph 
    { 
    // Forward Declarations 
    private: 
    class vertex; 
    class edge; 
    template <class U> 
    friend class graph_algorithm; 

    public : 
    explicit graph(const std::vector<std::pair<T, T> > &vertices); 
    ~graph() 
    {} 
    void insert_vertex_pair_by_keys(T key1, T key2); 
    const std::list<vertex> &vertices() const {return m_Vertices;} 

    // Private contained classes 
    private: 
    struct edge 
    { 
     edge(vertex *edge, T weight) : 
     m_Edge(edge), 
     m_Weight(weight) 
     {} 
     vertex *m_Edge; 
     T m_Weight; 
    }; // END EDGE 

    class vertex 
    { 
    public: 
     vertex(T key) : 
     m_Key(key) 
     {} 
     void connect_edge(vertex *adjacent); 
     const T key() const {return m_Key;} 
     const std::list<edge> &edges() const {return m_Edges;} 
    private: 
     std::list<edge> m_Edges; 
     T m_Key; 
     bool contains_edge_to_vertex_with_key(const T key); 
    }; // END VERTEX 

    // Private methods and member variables 
    private: 
    std::list<vertex> m_Vertices; 
    vertex *contains_vertex(const T key); 
    }; 
} 

/*! 
* Constructor of graph: Take a pair of vertices as connection, attempt 
* to insert if not already in graph. Then connect them in edge list 
*/ 
template <class T> 
Graph::graph<T>::graph(const std::vector<std::pair<T, T> > &vertices_relation) 
{ 

#ifndef NDEBUG 
    std::cout << "Inserting pairs: " << std::endl; 
#endif 

    typename std::vector<std::pair<T, T> >::const_iterator insert_it = vertices_relation.begin(); 
    for(; insert_it != vertices_relation.end(); ++insert_it) { 

#ifndef NDEBUG 
    std::cout << insert_it->first << " -- > " << insert_it->second << std::endl; 
#endif 

    /* 
    * Insert vertex by key pairs into the graph 
    */ 
    insert_vertex_pair_by_keys(insert_it->first, insert_it->second); 
    } 

#ifndef NDEBUG 
    std::cout << "Printing results: " << std::endl; 
    typename std::list<vertex>::iterator print_it = m_Vertices.begin(); 
    for(; print_it != m_Vertices.end(); ++print_it) { 
    std::cout << print_it->key() << " --| "; 
    typename std::list<edge>::const_iterator edge_it = print_it->edges().begin(); 
    for(; edge_it != print_it->edges().end(); ++edge_it) { 
     std::cout << edge_it->m_Edge->key() << " --> "; 
    } 
    std::cout << std::endl; 
    std::cout << "|" << std::endl; 
    std::cout << "V" << std::endl; 
    } 
#endif 
} 

/*! 
* Takes in a value of type T as a key and 
* inserts it into graph data structure if 
* key not already present 
*/ 
template <typename T> 
void Graph::graph<T>::insert_vertex_pair_by_keys(T key1, T key2) 
{ 
    /* 
    * Check if vertices already in graph 
    */ 
    Graph::graph<T>::vertex *insert1 = contains_vertex(key1); 
    Graph::graph<T>::vertex *insert2 = contains_vertex(key2); 

    /* 
    * If not in graph then insert it and get a pointer to it 
    * to pass into edge. See() for information on how 
    * to build graph 
    */ 
    if (insert1 == NULL) { 
    m_Vertices.push_back(vertex(key1)); 
    insert1 = contains_vertex(key1); 
    } 
    if (insert2 == NULL) { 
    if (key1 != key2) { 
     m_Vertices.push_back(vertex(key2)); 
    } 
    insert2 = contains_vertex(key2); 
    } 

#ifndef NDEBUG 
    assert(insert1 != NULL && "Failed to insert first vertex"); 
    assert(insert2 != NULL && "Failed to insert second vertex"); 
#endif 

    /*! 
    * At this point we should have a vertex to insert an edge on 
    * if not throw an error. 
    */ 
    if (insert1 != NULL && insert2 != NULL) { 
    insert1->connect_edge(insert2); 
    insert2->connect_edge(insert1); 
    } else { 
    throw std::runtime_error("Unknown"); 
    } 
} 

/*! 
* Search the std::list of vertices for key 
* if present return the vertex to indicate 
* already in graph else return NULL to indicate 
* new node 
*/ 
template <typename T> 
typename Graph::graph<T>::vertex *Graph::graph<T>::contains_vertex(T key) 
{ 
    typename std::list<vertex >::iterator find_it = m_Vertices.begin(); 
    for(; find_it != m_Vertices.end(); ++find_it) { 
    if (find_it->key() == key) { 
     return &(*find_it); 
    } 
    } 
    return NULL; 
} 

/*! 
* Take the oposing vertex from input and insert it 
* into adjacent list, you can have multiple edges 
* between vertices 
*/ 
template <class T> 
void Graph::graph<T>::vertex::connect_edge(Graph::graph<T>::vertex *adjacent) 
{ 
    if (adjacent == NULL) 
    return; 

    if (!contains_edge_to_vertex_with_key(adjacent->key())) { 
    Graph::graph<T>::edge e(adjacent, 1); 
    m_Edges.push_back(e); 
    } 
} 

/*! 
* Private member function that check if there is already 
* an edge between the two vertices 
*/ 
template <class T> 
bool Graph::graph<T>::vertex::contains_edge_to_vertex_with_key(const T key) 
{ 
    typename std::list<edge>::iterator find_it = m_Edges.begin(); 
    for(; find_it != m_Edges.end(); ++find_it) { 
    if (find_it->m_Edge->key() == key) { 
     return true; 
    } 
    } 
    return false; 
} 
#endif 

#ifndef GRAPH_ALGORITHMS_H_ 
#define GRAPH_ALGORITHMS_H_ 

#include "graph.h" 

namespace Graph 
{ 
    template <class T> 
    class graph_algorithm 
    { 
    // Forward declarations of 
    // internal classes 
    private : 
    class vertex_comparer; 

    public : 
    graph_algorithm(graph<T> *&graph) : 
     m_Graph(graph) 
    {} 

    // Definition of internal classes 
    private : 
    class vertex_comparer 
    { 
    public: 
     bool operator()(graph<T>::vertex &v1, graph<T>::vertex &v2) 
     { 
     (t1.key() < t2.key()) ? return true : return false; 
     } 
    }; 
    private : 
    graph<T> *m_Graph; 
    }; 
} 

#endif 

#include "graph_algorithms.h" 
#include "graph.h" 
#include <cstdlib> 

int main(int argc, char *argv[]) 
{ 
    std::vector<std::pair<int, int> > graph_vect; 
    for (int i = 0; i < 100; i++) { 
    graph_vect.push_back(std::pair<int, int>(rand()%20, rand()%20)); 
    } 
    Graph::graph<int> my_graph(graph_vect); 
    return 0; 
} 
+0

你的頂點類是私有的。 – 2012-04-08 16:43:14

+0

我認爲這是錯誤的類邊緣的前向聲明:而不是代碼結構邊緣。 – CapelliC 2012-04-08 16:55:32

+0

@chac感謝您的糾正。它沒有被使用,所以編譯器從不抱怨 – 2012-04-08 17:08:34

回答

2

作爲一個規則,如果你看到編譯錯誤使用模板的時候,那麼第一幾懷疑應該是一個你已經忘記爲依賴寫typename NT類型,比如這個:

bool operator()(graph<T>::vertex &v1, graph<T>::vertex &v2) 

它最好是這樣的:

bool operator()(typename graph<T>::vertex &v1, typename graph<T>::vertex &v2) 

你看到typename?同樣,您需要在代碼中隨處編寫typename - 無論您使用的是依賴類型。

如果你想知道什麼是依賴類型,並在那裏把爲什麼把typename與依賴的類型,那麼閱讀:

除此之外,你還需要了解private成員和public成員之間的區別 - 是他們類型變量。在你的情況下,嵌套的類型是private,我認爲,應該是public

+0

但引用類聲明爲朋友。不夠嗎? – CapelliC 2012-04-08 16:55:22

+0

@chac:我沒注意到。另外,我不確定語法。 – Nawaz 2012-04-08 17:01:16

+1

@Nawaz感謝您的幫助,您對typename忽略了這一點是正確的。是的,我做了頂點和邊緣私人因爲我不希望用戶不必擔心這個概念。如果他們想要來自頂點或邊緣的數據,我會提供一個T&get_data()方法。但我仍然希望圖算法能夠訪問它們,因爲它需要它。所以我把它變成了朋友。 – 2012-04-08 17:13:13