I found an open source class library for Graphs. When I included it in my project it has many errors and I tried to fix them. But there is a compile error that I can not solve it.
Base class:
template <typename K, typename W, typename T>
class _base_graph
{
//...
protected:
std::map<K, T> nod;
std::list<edge> edg;
};
Derived class:
template <typename K, typename T = void*>
class graph : public _base_graph<K, void*, T>
{
//...
public:
void add_edge(const K& k1, const K& k2);
};
Method body:
template <typename K, typename T>
void graph<K, T>::add_edge(const K& k1, const K& k2)
{
if (nod.find(k1) == nod.end() || nod.find(k2) == nod.end()) // <-- error!!
throw std::string("add_edge: Node does not exist");
// ...
}
But my gcc compiler show me an error:
error: ‘nod’ was not declared in this scope
You can find and test mycode in this online compiler.
You need
or
The base and the derived classes are templates, and in your code
nodis a non-dependent name, and so is looked up at the point ofgraph‘s declaration. This is the first phase of the two-phase lookup. At this stage, it is impossible for the compiler (provided it follows the name lookup rules of the standard) to know whatnodmeans, because it does not consider the base class until the second phase. So it is necessary to tell the compiler thatnodshould be looked up in the second phase. To do this, we explicitly tell it thatnodis in a base class by using one of the forms above.The reason for this behaviour is that at the point of the derived class’ definition, it should not possible to know what
_base_graph<K, void*, T>::contains, to allow for specializations of the template that add and even hide names. So the trick above makes sure that the names are looked up at the point of the derived class’ instantiation, when all the information is available.In summary, there are two issues in play here:
nodis not a dependent name, so it would be looked up in the first phase.nod, is not available until the second phase, so the name cannot be resolved.By using
this->nodor_base_graph<K, void*, T>::nod, we are explicitly dealing with a dependent name, forcing the lookup to take place in the second phase.See points 7 to 10 here.
Thanks to @DavidRodriguez-dribeas for clarifying some of the finer points of the two phase look-up.