masoud
masoud

Reputation: 56549

Protected member is unknown for derived class

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.

Upvotes: 3

Views: 208

Answers (2)

juanchopanza
juanchopanza

Reputation: 227608

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.

Upvotes: 8

pmr
pmr

Reputation: 59841

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.

Upvotes: 3

Related Questions