3

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.

2 Answers 2

8

You need

this->nod.find(k2);

or

_base_graph<K, void*, T>::nod.find ....;

The base and the derived classes are templates, and in your code nod is a non-dependent name, and so is looked up at the point of graph'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 what nod means, because it does not consider the base class until the second phase. So it is necessary to tell the compiler that nod should be looked up in the second phase. To do this, we explicitly tell it that nod is 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:

  1. nod is not a dependent name, so it would be looked up in the first phase.
  2. The base class template, which declared nod, is not available until the second phase, so the name cannot be resolved.

By using this->nod or _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.

10
  • Thanks, but why there is not same issue for method and they do not need this-> ?
    – masoud
    Commented Nov 13, 2012 at 11:12
  • @MasoudM. You would have the same problem with a method, at least with a standards compliant compiler. Commented Nov 13, 2012 at 11:16
  • The description is good, but it would be better if you used proper terms, in particular dependent*/*non-dependent name; and explained how the extra qualification transform a name from the second set to the first. Commented Nov 13, 2012 at 12:45
  • @DavidRodríguez-dribeas that was my intention before the edit, but I have found base<T>::name described as both dependent and non-dependent, so I will have to wait until I can have a look at the standard later. This stuff still confuses me sometimes. Commented Nov 13, 2012 at 12:51
  • @juanchopanza: base<T>::name is clearly dependent on T, how could it not depend on T? Commented Nov 13, 2012 at 14:18
3

nod is a member of a dependent base (one that depends on template parameters). You either need to qualify the call with the name of the base, e.g. _base_graph<K, void*, T>::nod or with this->nod.

Alternatively you can also bring in names with using _base_graph<K, void*, T>::nod in either function or class scope.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.