0

I have the code below, the compiler error is: Why can't graph_algorithm find the vertex class inside the graph class?

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;
}
Matthew Hoggan
  • 6,723
  • 13
  • 63
  • 120

1 Answers1

2

As a rule, if you see compilation errors when working with templates, then one of the first few doubts should be that you've forgotten to write typename for dependent types, such as this:

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

which should rather be this:

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

Do you see typename? Likewise, you need to write typename everywhere in your code as well - wherever you're using dependent types.

If you want to know what is dependent types, and where to put and why to put typename with dependent types, then read this :

Apart from that, you also need to understand the difference between private members and public members - be them types or variables. In your case, the nested-types are private, which I think, should be public.

Community
  • 1
  • 1
Nawaz
  • 327,095
  • 105
  • 629
  • 812
  • but the referring classes are declared friend. Doesn't suffice? – CapelliC Apr 08 '12 at 16:55
  • @chac: I didn't notice that. Also, I'm not sure about the syntax. – Nawaz Apr 08 '12 at 17:01
  • 1
    @Nawaz thanks for the help, you are right about typename overlooked that. And yes I made the vertex and edge private becuase I don't want users to have to worry about the concept. If they want data from vertex or edge, I would provide a T &get_data() method. But I still want graph algorithms to have access to these since it needs it. So i made it a friend. – Matthew Hoggan Apr 08 '12 at 17:13