Dinesh
Dinesh

Reputation: 66

Deriving a class from a class template

I am new to C++. During my learning phase I encountered with below issue. I am trying to derive a class stack from a class template Queue. Compiler throws below error in constructor of stack

..\src\TrainingDay2.cpp:44:3: error: 'b' was not declared in this scope
   b=a;

Please help to find out the root cause.

#include <iostream>
using std::cout;
using std::endl;

template<class T> class Queue //Base class
{
private:
    T ArrQueue[20];
protected:
    T* a;
    T* b;
public:

    Queue() { cout<<"QUEUE CONST "<<  endl; }
    void push(T x);
    void pop(void);
};


template <class T>
class stack :public Queue<T> // Derived class
{
public:
    stack():Queue<T>() {
        b=a;
    }
    void pop() {
        b--;
    }
};


int main()
{
    stack<int> S;
    return 0;
}

Upvotes: 2

Views: 115

Answers (3)

The reason is that inside a template, two-phase name lookup rules apply:

  • Names which do not depend on template parameters are looked up (=resolved) when the template is defined (=parsed).

  • Names which do depend on template parameters are looked up when the template is instantiated (when you provide the template arguments).

  • Base classes which depend on template parameters are only searched during name lookup at instantiation time.

The reason for this two-phase lookup is that until the template arguments are known, the compiler cannot know what the definition of the base class (or other dependent construct) will be. Remember that template specialisation exists.

You need to somehow tell the compiler that the name b is dependent. You basically have three ways to do that:

  1. Prefix the name with this->; since you're in a class template, all your members depend on template parameters implicitly:

    this->b = a;
    
  2. Use full qualification for the name. This will make the dependency on template parameters explicit:

    Queue<T>::b = a;
    
  3. Put a using declaration into your class to inform the compiler that the name comes from a dependent base class:

    template <class T>
    class stack :public Queue<T> // Derived class
    {
    protected:
        using Queue<T>::b;
    
    public:
        stack():Queue<T>()
        {
            b=a;
        }
         void pop()
        {
            b--;
        }
    };
    

Upvotes: 2

senfen
senfen

Reputation: 907

In a template definition, unqualified names will no longer find members of a dependent base (as specified by [temp.dep]/3 in the C++ standard). For example, You must make the names dependent, e.g. by prefixing them with this->.

gcc-problem-using-a-member-of-a-base-class-that-depends-on-a-template-argument

And yes, it can be valid in VS.

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

Because the base class is a template, whose instantiation depends on a template parameter of the derived class, and you're trying to name a member of the base class, two-phase lookup mandates that you write this->b, not b.

(And that default constructor call is not needed.)

stack()
{
    this->b = this->a;
}

void pop()
{
    this->b--;
}

(live demo)

Welcome to C++… :P


[C++11: 14.6.2/3]: In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [..]

Upvotes: 2

Related Questions