Reputation: 92874
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
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
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.
Member
i.e Base<Type>::member
this->member
.Upvotes: 8
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
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
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