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

2

7

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)

Soucy answered 16/4, 2012 at 9:0 Comment(3)
Joachim Pileborg gave you the answer. In addition to that, the provided code has other problems preventing it from compiling.Radford
Is this the actual code? There are no trailing semi-colons after class definitions and the scope operator for int B<T>:f() is incorrect plus no semi-colon at the error line.Norbertonorbie
oh, it's just a typing mistake. I fixed it.Soucy
B
16

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.

Bangup answered 16/4, 2012 at 9:19 Comment(2)
A dependent name is a name that does not depend on a template parameter -> A dependent name is a name that depend on a template parameter : )Nu
@czxyl: Almost half a decade to uncover this mistake :D Thanks for the hint :)Bangup
S
1

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.

Shah answered 16/4, 2012 at 9:31 Comment(4)
"The dependent names are not known" -> This does not make sense in C++ parlance. A name might be dependent or not, e.g. with typename T, A<T>::x is a dependent name, x is not. It may make sense for you as the programmer that x is a dependent name, but technically, x is not a dependent name.Bangup
-1: "its names are non-dependent and consequently must be looked up" -> This is wrong. There can be member names that are dependent. Example: ideone.com/zIa7kBangup
Sorry, "... the dependent names cannot be resolved (...), which is why the compiler is not able to determine that it is defined in the base class" would have been more appropriate.Shah
But I am afraid even that would not be fully correct. Microsofts compiler once did that, because it is possible if the names exist in templates visible, but the standard forbids it because it might grab an incorrect symbol (imagine you have a value member 'm' in the primary template, and in a specialized template, you have a typename 'm'; with microsofts old compiler, this would have resulted in a wrong program).Bangup

© 2022 - 2024 — McMap. All rights reserved.