This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 8 years ago.
Why can't a C++ compiler recognize that g() and b are inherited members of Superclass as seen in this code:
template<typename T> struct Superclass {
protected:
int b;
void g() {}
};
template<typename T> struct Subclass : public Superclass<T> {
void f() {
g(); // compiler error: uncategorized
b = 3; // compiler error: unrecognized
}
};
If I simplify Subclass and just inherit from Subclass<int> then it compiles. It also compiles when fully qualifying g() as Superclass<T>::g() and Superclass<T>::b. I'm using LLVM GCC 4.2.
Note: If I make g() and b public in the superclass it still fails with same error.
This can be amended by pulling the names into the current scope using using:
template<typename T> struct Subclass : public Superclass<T> {
using Superclass<T>::b;
using Superclass<T>::g;
void f() {
g();
b = 3;
}
};
Or by qualifying the name via the this pointer access:
template<typename T> struct Subclass : public Superclass<T> {
void f() {
this->g();
this->b = 3;
}
};
Or, as you’ve already noticed, by qualifying the full name.
The reason why this is necessary is that C++ doesn’t consider superclass templates for name resolution (because then they are dependent names and dependent names are not considered). It works when you use Superclass<int> because that’s not a template (it’s an instantiation of a template) and thus its nested names are not dependent names.
Konrad's answer doesn't ask or answer the final "why" in all of this. It's not just the C++ committee arbitrarily saying "hey, give up on dependent names, nobody likes them anyway". Rather, the compiler does some checking of the templates even before they're instantiated, and it can't make any sense of g() or b until it knows T, as it can't - in general - select between possible specialisations of the base class (e.g. SuperClass<X> may have int b while SuperClass<Y> has void b() and SuperClass<Z> doesn't have b at all). The more explicit forms are just saying "trust me - this must come from the base class at instantiation time (otherwise there'll be a compiler error then)".
Related
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 5 years ago.
Consider the following code:
template<class T> class Foo
{
public:
Foo() { a = 1; }
protected:
int a;
};
template<class T> class Bar : public Foo<T>
{
public:
Bar() { b = 4; };
int Perna(int u);
protected:
int b;
};
template<class T> int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
return (a + b) * u; // This doesn't
}
g++ 3.4.6, 4.3.2 and 4.1.2 give error
test.cpp: In member function `int Bar<T>::Perna(int)':
test.cpp:25: error: `a' was not declared in this scope
g++ 2.96 and MSVC 6, 7, 7.1, 8 and 9 accept it, as do (at least) older Intel and SGI c++ compilers.
Do the new Gnu C++ compiler obey the standard or not? If they do, what is the rationale behind that inheriting class is not able to see a protected inherited member variable?
Also, if there's
int A() { return a; }
in Foo, I get error
test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available
test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
when I try to use it in a member function of Bar.
I find that curious as well: Bar inherits Foo, so I think it's obvious that A() in scope of Bar is Foo::A().
The later GCC versions correctly implement the standard.
The standard specifies that unqualified names in a template are non-dependent and must be looked up when the template is defined. The definition of a dependent base class is unknown at that time (specializations of the base class template may exist) so unqualified names are unable to be resolved.
This is true for both variable and function names declared in the base class.
As you have observed the solution is to provide the qualified name of the variable or function, or to provide a "using" declaration. E.g.
template<class T>
int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
c = this->a * 4; // and this
using Foo<T>::a;
c = a * 4; // and with 'using', so should this
}
(I'm actually not 100% sure about the correct syntax for the using version and can't test from here, but you get the idea).
The error message that GCC gives shows that your version of GCC still had a bug that is only resolved in GCC4.7 trunk versions. Older versions, including GCC4.1 will happily accept following code
template<typename T>
struct A {
void f(int) { }
};
template<typename T>
struct B : A<T> {
void g() { T t = 0; f(t); }
};
int main() {
B<int> b; b.g();
}
GCC will look up f in f(t) within the base class A<T> and will find the declaration in the base class. GCC does that because f is dependent, because there are arguments to f that "depend on a template parameter" (look at its error message it gave you!). But the Standard forbids GCC to do that for two reasons
The Standard says that use of unqualified names will never find a declaration in a dependent base class no matter whether the name is dependent.
The Standard says that dependent lookup of a function name at instantiation time will only do ADL.
GCC 4.7 implements the Standard correctly in that regard.
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 7 years ago.
I have a templated class that I inherit from, and access through the derived class the base class members.
I can't access them without using "this" and I find a descent reason why.
If I understand correctly, when I use a template, a copy of the templated code is being made with a specialization, and only then it compiles. Meaning if I write vector<int> the compiler makes a copy of vector and replaces all the "T" with "int".
If that is the case, I don't see why there should be any difference between templates and non-templated code.
template <typename T>
class b
{
protected:
int myMember;
};
template<typename T>
class e : public b<T>
{
public:
void dosomething()
{
this->myMember = 2; // Everything is perfect
myMember = 2; // Doesn't compile in GCC, can't find the member
}
};
int main()
{
e<int> mye;
mye.dosomething();
}
Because the base class is dependent on template parameters, the base members are not considered during unqualified lookup.
When you use this-> you use class member lookup instead, which will examine the base class members, even if it is a dependent type.
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 8 years ago.
Why can't a C++ compiler recognize that g() and b are inherited members of Superclass as seen in this code:
template<typename T> struct Superclass {
protected:
int b;
void g() {}
};
template<typename T> struct Subclass : public Superclass<T> {
void f() {
g(); // compiler error: uncategorized
b = 3; // compiler error: unrecognized
}
};
If I simplify Subclass and just inherit from Subclass<int> then it compiles. It also compiles when fully qualifying g() as Superclass<T>::g() and Superclass<T>::b. I'm using LLVM GCC 4.2.
Note: If I make g() and b public in the superclass it still fails with same error.
This can be amended by pulling the names into the current scope using using:
template<typename T> struct Subclass : public Superclass<T> {
using Superclass<T>::b;
using Superclass<T>::g;
void f() {
g();
b = 3;
}
};
Or by qualifying the name via the this pointer access:
template<typename T> struct Subclass : public Superclass<T> {
void f() {
this->g();
this->b = 3;
}
};
Or, as you’ve already noticed, by qualifying the full name.
The reason why this is necessary is that C++ doesn’t consider superclass templates for name resolution (because then they are dependent names and dependent names are not considered). It works when you use Superclass<int> because that’s not a template (it’s an instantiation of a template) and thus its nested names are not dependent names.
Konrad's answer doesn't ask or answer the final "why" in all of this. It's not just the C++ committee arbitrarily saying "hey, give up on dependent names, nobody likes them anyway". Rather, the compiler does some checking of the templates even before they're instantiated, and it can't make any sense of g() or b until it knows T, as it can't - in general - select between possible specialisations of the base class (e.g. SuperClass<X> may have int b while SuperClass<Y> has void b() and SuperClass<Z> doesn't have b at all). The more explicit forms are just saying "trust me - this must come from the base class at instantiation time (otherwise there'll be a compiler error then)".
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ Inherited template classes don't have access to the base class
I'm experiencing problems with templates and inheritance. Simply, I have a template class which I want another template class to inherit from. I don't understand why members of base class are not visible within deriving class? Though without using templates everything works as expected. For example:
template <typename T>
class Foo
{
public:
T x;
T y;
void doX(){ x = x+1; }
void doY(){y++;}
protected:
T a;
T b;
void doA(){a++;}
};
template <typename T>
class Bar : public Foo<T>
{
public:
void doX(){x++; y++;} // ERROR
void doY(){x++; y++;} // ERROR
void doA(){a++;b++;} // ERROR
};
These variables are dependent names (read The Dreaded Two-Phase Name Lookup for details), so you need to use this as:
void doX(){ this->x++; this->y++; }
Usually this-> is not required as it is implicit. But here it is required. Actually explicit this-> tells the compiler to look up the name in the second phase when the base class is instantiated, as this case uses two-phase name lookup mechanism.
Or you could qualify them with base class as:
template <typename T>
class Bar : public Foo<T>
{
typedef Foo<T> base; //add this friendly typedef!
public:
void doX(){ base::x++; base::y++;}
//...
};
In this case, the fact that the names cannot be looked-up untill base (which is a typedef of Foo<T>) is instantiated, becomes more obvious (to humans eyes) in my opinion.
If the base class depends on a template parameter, then its members aren't directly available in the derived class definition. Until the template is instantiated, the compiler doesn't know what the base class will contain, and so it won't look up any names from there.
You can force it to treat the names as members by qualifying them:
void doX(){this->x++; Foo<T>::y++;} // OK: both forms specify that it's a member
Write this->x, this->y instead of x, y in derived class functions.
Try referring to the variables using the base class scope:
Foo<T>::x
or use this
this->x
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 5 years ago.
Consider the following code:
template<class T> class Foo
{
public:
Foo() { a = 1; }
protected:
int a;
};
template<class T> class Bar : public Foo<T>
{
public:
Bar() { b = 4; };
int Perna(int u);
protected:
int b;
};
template<class T> int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
return (a + b) * u; // This doesn't
}
g++ 3.4.6, 4.3.2 and 4.1.2 give error
test.cpp: In member function `int Bar<T>::Perna(int)':
test.cpp:25: error: `a' was not declared in this scope
g++ 2.96 and MSVC 6, 7, 7.1, 8 and 9 accept it, as do (at least) older Intel and SGI c++ compilers.
Do the new Gnu C++ compiler obey the standard or not? If they do, what is the rationale behind that inheriting class is not able to see a protected inherited member variable?
Also, if there's
int A() { return a; }
in Foo, I get error
test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available
test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
when I try to use it in a member function of Bar.
I find that curious as well: Bar inherits Foo, so I think it's obvious that A() in scope of Bar is Foo::A().
The later GCC versions correctly implement the standard.
The standard specifies that unqualified names in a template are non-dependent and must be looked up when the template is defined. The definition of a dependent base class is unknown at that time (specializations of the base class template may exist) so unqualified names are unable to be resolved.
This is true for both variable and function names declared in the base class.
As you have observed the solution is to provide the qualified name of the variable or function, or to provide a "using" declaration. E.g.
template<class T>
int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
c = this->a * 4; // and this
using Foo<T>::a;
c = a * 4; // and with 'using', so should this
}
(I'm actually not 100% sure about the correct syntax for the using version and can't test from here, but you get the idea).
The error message that GCC gives shows that your version of GCC still had a bug that is only resolved in GCC4.7 trunk versions. Older versions, including GCC4.1 will happily accept following code
template<typename T>
struct A {
void f(int) { }
};
template<typename T>
struct B : A<T> {
void g() { T t = 0; f(t); }
};
int main() {
B<int> b; b.g();
}
GCC will look up f in f(t) within the base class A<T> and will find the declaration in the base class. GCC does that because f is dependent, because there are arguments to f that "depend on a template parameter" (look at its error message it gave you!). But the Standard forbids GCC to do that for two reasons
The Standard says that use of unqualified names will never find a declaration in a dependent base class no matter whether the name is dependent.
The Standard says that dependent lookup of a function name at instantiation time will only do ADL.
GCC 4.7 implements the Standard correctly in that regard.