Accessing inherited variable from templated parent class [duplicate] - c++

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.

Related

Why can't a typedef type be used to declare its parent class' ctors? [duplicate]

This question already has answers here:
A 'using' statement compiles with g++, fails compilation with clang
(2 answers)
Closed 2 years ago.
template<typename>
struct A
{
int n;
A(bool)
{}
};
template<typename>
struct B
{
struct C : A<B>
{
using Base = A<B>;
using A<B>::A; // ok
using Base::n; // ok
// error: dependent using declaration resolved to type without 'typename'
using Base::A;
};
C get() const
{
return C(true);
}
};
int main()
{
auto b = B<int>();
b.get();
}
The error is described in the code.
Why can't a typedef type be used to declare its parent class' ctors?
Similar behaviour was earlier reported as a possible Clang bug: [Bug 23107] Constructor inheritance on template not working correctly.
Richard Smith's comment on this report:
The C++ committee have discussed this case and did not intend for that syntax
to be valid. Use using myBase::myBase; instead to declare an inheriting constructor.
So, you should write using Base::Base; instead of using Base::A;. After this fix, your code compiles with Clang.
As someone else commented, your code compiles on the latest GCC and MSVC without problems.
Your problem seems to happen on Clang.
The standard has something similar to this naming issue for destructors (source):
In a qualified-id of the form:
[...] type-name::~type-name
the second type-name is looked up in the same scope as the first.
struct C {
typedef int I;
};
typedef int I1, I2;
extern int* p;
extern int* q;
p->C::I::~I(); // I is looked up in the scope of C
q->I1::~I2(); // I2 is looked up in the scope of the postfix-expression
struct A {
~A();
};
typedef A AB;
int main() {
AB* p;
p->AB::~AB(); // explicitly calls the destructor for A
}
But I couldn't find anything that clear related to constructors. I'd assume the behavior should be the same, but only someone more experienced with the Standard could confirm.
Interestingly enough, if you make your A class not a template, it works on Clang as well:
struct A
{
A(bool) {}
};
template<typename>
struct B
{
struct C : A
{
using Base = A;
using Base::A;
};
//...
So maybe that's a Clang bug?
One thing you can do is use Base's constructor: Base::Base:
struct C : A<B>
{
using Base = A<B>;
using Base::Base;
};

protected inheritance with template classes [duplicate]

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.

error with pointer_name is not declared in this scope [duplicate]

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)".

Avoid LLVM errors in templates when accessing parent template's members [duplicate]

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.

accessing protected members of superclass in C++ with templates [duplicate]

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)".