Accessing inherited variable from templated parent class

14,118

Solution 1

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

Solution 2

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

  1. 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.

  2. 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.

Share:
14,118
Admin
Author by

Admin

Updated on June 15, 2022

Comments

  • Admin
    Admin about 2 years

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