iteong iteong - 2 months ago 9
C++ Question

Returning an iterator to graph node with function templates

I have 2 files, one is a .h file which contains my declarations and another is a .tem file which contains the implementation of my .h file. I'm having issues with the iterator for begin() and end() for my graph node iterator (shown below in "// Iterators for Graph nodes"), which is supposed to return the iterator pointing at the begin or end of an iterated graph.

The following is my code in the Graph.h:

#ifndef _Graph_h
#define _Graph_h

#include <vector>
#include <algorithm>
#include <string>
#include <memory>
#include <iostream>
#include <exception>
#include <map>
#include <set>
#include <typeinfo>


namespace gdwg {

template <typename N, typename E> class Graph; // function prototype for Graph class

//-----------------------------------------------------------
// Iterators for Graph with Nodes N and Edges E
//-----------------------------------------------------------

// Iterator class for Node N
template <typename N, typename E> class Node_Iterator {

******* Some code for public and private members of Node_Iterator

};

// Iterator class for Edge E
template <typename N, typename E> class Edge_Iterator {

******* Some code for public and private members of Edge_Iterator

};

template <typename N, typename E> class Graph {

private:
struct Node;
struct Edge;

struct Node {
N val_;
int numEdges_;
std::set<std::shared_ptr<Edge>> edges_;
Node() {}
Node(const N x) : val_{x} { numEdges_=0; }
void printNode(N n);
~Node();
void update();
};

struct Edge {
std::weak_ptr<Node> orig;
std::weak_ptr<Node> dest;
E val_;
Edge(std::shared_ptr<Node> o, std::shared_ptr<Node> d, E x);
Edge() {};
void printEdge();
~Edge();
};

public:

friend class Node_Iterator<N, E>;
friend class Edge_Iterator<N, E>;


******* Some code for public members of Graph

// Iterators for Graph nodes
Node_Iterator<N, E> begin() const;

Node_Iterator<N, E> end() const;


private:
std::map< N, std::shared_ptr<Node> > nodes_;


};

#include "Graph.tem" // definition and implementation of Node_Iterator, Edge_Iterator and Graph classes

}

#endif


This is the definition in the .tem file for the iterators:

template <typename N, typename E>
Graph<N, E>::Node_Iterator<N, E> Graph<N, E>::begin() const {
return Node_Iterator<N, E>(&Graph<N, E>::nodes_);
}

template <typename N, typename E>
Graph<N, E>::Node_Iterator<N, E> Graph<N, E>::end() const {
return Node_Iterator<N, E>(nullptr);
}


When I tried to compile it, there was the following error code (I will just put the error code for begin() coz the end() error is similar):

tests/Graph.tem:336:14: error: non-template ‘Node_Iterator’ used as template
Graph<N, E>::Node_Iterator<N, E> Graph<N, E>::begin() const {
^~~~~~~~~~~~~
tests/Graph.tem:336:14: note: use ‘gdwg::Graph<N, E>::template Node_Iterator’ to indicate that it is a template
tests/Graph.tem:336:1: error: need ‘typename’ before ‘gdwg::Graph<N, E>::Node_Iterator’ because ‘gdwg::Graph<N, E>’ is a dependent scope
Graph<N, E>::Node_Iterator<N, E> Graph<N, E>::begin() const {
^~~~~~~~~~~


So I did what it said and added "typename" in front of Graph and also made it a template. But it came up with this error instead:

tests/Graph.tem:336:52: error: prototype for ‘typename gdwg::Graph<N, E>::Node_Iterator<N, E> gdwg::Graph<N, E>::begin() const’ does not match any in class ‘gdwg::Graph<N, E>’
typename Graph<N, E>::template Node_Iterator<N, E> Graph<N, E>::begin() const {
^~~~~~~~~~~
In file included from tests/test1.cpp:3:0:
tests/Graph.h:322:23: error: candidate is: gdwg::Node_Iterator<N, E> gdwg::Graph<N, E>::begin() const
Node_Iterator<N, E> begin() const;
^~~~~


So I removed the Graph in front of begin() as I thought it was the problem, but got another error instead:

tests/Graph.tem:336:60: error: non-member function ‘typename gdwg::Graph<N, E>::Node_Iterator<N, E> gdwg::begin()’ cannot have cv-qualifier
typename Graph<N, E>::template Node_Iterator<N, E> begin() const {
^~~~~


Can someone tell me what I'm doing wrong?

Answer

Node_Iterator is not a sub-class of Graph so Graph<N, E>::Node_Iterator<N, E> cannot be found. Simply change the definition to this should work:

template <typename N, typename E>  
Node_Iterator<N,E> Graph<N,E>::begin() const { 
    return Node_Iterator<N,E>(&Graph<N, E>::nodes_);
}