Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I use variable of parent class that is template class?

a.h

template <typename T>
class A
{
    public:
    int a;
}

b.h

template <typename T>
class B : public A<T>
{
   public:
   int f();
}

template <typename T>
int B<T>::f()
{
    int t;
    t = this->a; //Okay
    t = a //Error
    return 0;
}

why does error happen when I don't use this->?

Can I omit this-> with using some method?

(I fixed some mistakes)

like image 441
Gimun Eom Avatar asked Apr 16 '12 09:04

Gimun Eom


2 Answers

There are two phases in template instantiation ("Two Phase Name Lookup").

In the first phase, all non-dependent names are resolved (looked up). In the second phase, dependent names are resolved.

A dependent name is a name which depends on a template parameter, e.g.:

template <typename T>
void foo() {
    x = 0;    // <- Non-dependent, nothing in that refers to "T".
              //    Thus looked up in phase 1, therefore, an 'x' must be
              //    visible.

    T::x = 0; // <- Dependent, because it depends on "T".
              //    Looked up in phase 2, which is when it must be visible.
}

Now, you write:

t = this->a; //Okay
t = a //Error

This is exactly what I described. In the okay term, t is looked up in phase 2, because this depends on a template parameter.

The errorful term is looked up in phase 1, because nothing in that name depends on a template parameter. But in phase 1, no a is visible, because the compiler cannot introspect base class templates in phase 1, because templates can be specialized and at the point of instantiation, which can be remote from the primary template declaration, another specialization that has no a, might be visible.

Example:

    template <typename T>
    struct Base {
    };


    template <typename T>
    struct Derived : Base<T> {
        void foo() {
            this->a = 0; // As is valid. `this->a` is looked up in phase 2.
        }
    };


    template <> struct Base<int> {
        int a;            
    };


    int main () 
    {
            // The following declarations trigger phase 2 lookup.

            Derived<int>   di;  // valid, because a later specialized
                                // Base<int> is used and all symbols
                                // are resolved.

            Derived<float> df;  // not valid
    }

Btw, I have once written this-> is not only a matter of style in my very low frequency blog.

like image 192
Sebastian Mach Avatar answered Oct 14 '22 08:10

Sebastian Mach


B is a template, and thus its names are non-dependent and consequently must be looked up when the template is defined, not when it is instantiated. However, at the time of the definition of the template, the dependent names are not known (there might be specialisations of the base class template A which have not been seen so far), the compiler cannot resolve the unqualified name to the base class. You can either bring the name into the current scope through this-> qualification, by prefixing it with A<T>:: or with a using declaration:

template <typename T>
class B : public A<T>
{
   public:
   using A<T>::a;
   int f();
};

Also note that you where missing semi-colons after the class declarations and the line marked with the // Error comment.

like image 26
Michael Wild Avatar answered Oct 14 '22 09:10

Michael Wild