Prasoon Saurav
Prasoon Saurav

Reputation: 92874

Scope problems in template C++

Is there any scope problem in this program?

#include<iostream>

using namespace std;

template<class Type>
class Base
{
   public:
   Type member;
   Base(Type param): member(param){

   }
};

template<class Type>
class Derived: public Base<Type>
{
    public:               
    Derived(Type param):Base<Type>(param){
     //                       ^
     //                       |_______  Not writing Type here gives error, why?
    }
    void display()
    {
        cout << member; /** ERROR HERE **/
    }
};

int main()
{
   Derived<int> p(5);
   p.display();
   return 0;
}

I get error 'member' was not declared in this scope. How to fix the problems?

Upvotes: 1

Views: 5122

Answers (5)

sbi
sbi

Reputation: 224139

Your question is somewhat confusing. At first I thought you were asking about base<Type> in the member initialization list, then I thought you were asking about accessing member, then back to the first... Now I'm thinking you're asking both, so I'll answer both.


Not writing Type here gives error, why?

When you use a class template's name (my_class_templ), it refers to the template, which is not a type. In order to use it as a type, you need to provide template parameters (my_class_templ<int>, my_class_templ<T>). So wherever a type name is needed (and that includes the base class names in an initialization list), you need to provide template parameters.

You can omit the template parameter list for class templates names within the class template's definition. For example, a copy constructor can be declared as

 my_class_templ(const my_class_templ& rhs);

instead of

 my_class_templ<T>(const my_class_templ<T>& rhs);

This is just a little syntactic sugar, allowing you to type less.

However, outside of the class templates definition, you need to explicitly spell out all the template parameters. This is also true for derived classes:

my_dervied_class_templ(const my_derived_class_templ& rhs)
 : my_class_templ<T>(rhs)                          // need to spell out <T> here
{
}

I get error 'member' was not declared in this scope. How to fix the problems?

When your template is encountered first by the compiler, there's only its definition and no instantiations have been seen by the compiler yet. The compiler doesn't know whether, at a point of instantiation, there might be specializations of the template in scope or not. However, you could specialize your template for Base<T>::member to refer to something else or not to be defined entirely. (Say, a specialization Base<void> doesn't have a data member.) Therefore, the compiler must not speculate about the members of Base. Consequentially, they will not be looked up in Derived.

The result of this is that, if you need to refer to one of the members of Base, you need to tell the compiler that you expect a Base<T> to have such a member. This is done by fully qualifying its name: Base<Type>::member.

Upvotes: 8

Prasoon Saurav
Prasoon Saurav

Reputation: 92874

Not writing Type here gives error, why?

If you omit Type there is no way for the compiler to decide whether Base is a base class or is it a member of Derived. Specifying Type makes sure that Base is a template class [base class].

'member' was not declared in this scope

This is something to do with the rules for name lookup (dependent base classes).

C++03 [Section 14.6/8] says

When looking for the declaration of a name used in a template definition, the usual lookup rules (3.4.1, 3.4.2) are used for nondependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known (14.6.2).

Now Section 14.6.2/3 says

In the definition of a class template or a member of a class template, if a base class of the class template 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.

member is an unqualified name so the base class is not examined.

So you have two options.

  1. Use fully qualified name of Member i.e Base<Type>::member
  2. Use this->member.

Upvotes: 8

Chubsdad
Chubsdad

Reputation: 25537

Derived(Type param):Base<Type>(param){ 

That Base<Type> is required because the base of Derived is Base<T>. There is nothing called Base.

void display()   
{   
        //cout << member; /** ERROR HERE **/ 
        cout << this->member;
        cout << this>Base<Type>::member;  
}

Alternatively having a using declaration in the scope of 'Derived' is also a valid technique.

Upvotes: 0

sellibitze
sellibitze

Reputation: 28107

The C++ standard requires a compiler to do a "two phase lookup" for templates. That is, they are trying to resolve all non-dependent names (names that don't depend on template parameters) in the first phase when the template is parsed and all the dependent names in the second phase when the template is instantiated.

If you don't qualify member it is treated as a non-dependent name and lookup fails in the first phase. You can solve this by prepending this-> to it. This makes member a dependent name and lookup is delayed until you actually instantiate the template.

Upvotes: 2

Alexandre C.
Alexandre C.

Reputation: 56976

At the point where the compiler reads the template (not when it instanciates it), it cannot tell what Base<Type> is (it could be specialized), and therefore doesn't attempt to deduce it has a member member. You have to explicitely tell it: cout << this->Base<Type>::member;.

I think (check it, I'm not sure) that a using Base<Type>::member at class scope works too.

Upvotes: 2

Related Questions