Templates: Parent Class Member Variables Not Visible in Inherited Class

templates: parent class member variables not visible in inherited class

This is because the template parent of a template class is not instantiated during the compilation pass that first examines the template. These names appear to be non-dependent on the particular template instantiation, and therefore the definitions need to be available. (If you never look at the definition of arrayListType, then reading the code of unorderedArrayListType it would appear the list and length need to be some sort of globals.)

You'll need to tell the compiler explicitly that the names are in fact dependent on the instantiation of the parent.

One way, using this-> before all the inherited names: this->list, this->length.

Another way, using declarations: using arrayListType<elemType>::length; etc (for example in the private section of the derived class).


A FAQ entry on this: https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members

Visibility of members of base template class not directly inherited

You are using A<X> where a base class is expected.

[namespace.udecl]

3 In a using-declaration used as a member-declaration, each
using-declarator's nested-name-specifier shall name a base class of
the class being defined.

Since this appears where a class type is expected, it is known and assumed to be a type. And it is a type that is dependent on the template arguments, so it's not looked up immediately.

[temp.res]

9 When looking for the declaration of a name used in a template
definition, the usual lookup rules ([basic.lookup.unqual],
[basic.lookup.argdep]) are used for non-dependent names. The lookup of
names dependent on the template parameters is postponed until the
actual template argument is known ([temp.dep]).

So it's allowed on account of the compiler not being able to know any better. It will check the using declaration when the class is instantiated. Indeed, one can put any dependent type there:

template<bool> struct D{};

template <bool X>
struct C : public B<X> {
using D<X>::x;
C() { x = 1; }
};

This will not be checked until the value of X is known. Because B<X> can bring with it all sorts of surprises if it's specialized. One could for instance do this:

template<>
struct D<true> { char x; };

template<>
struct B<true> : D<true> {};

Making the above declaration be correct.

Can't access variable in template base class

Hehe, my favourite C++ oddity!

This will work:

void foo()
{
b = this->a;
// ^^^^^^
}

Unqualified lookup doesn't work here because the base is a template. That's just the way it is, and comes down to highly technical details about how C++ programs are translated.

Accessing variables from base template class in derived class constructor in C++

arr is a dependent name now. It depends on T. What if there is some T for which Base<T> is specialized to not have an arr? Specifically, from [temp.dep]:

In the definition of a class or class template, the scope of a dependent base class (14.6.2.1) is not examined
during unqualified name lookup
either at the point of definition of the class template or member or during
an instantiation of the class template or member.

Base<T> is a dependent base class - it depends on the template parameter T, so its scope is not examined during unqualified name lookup. The way around this is to use qualified name lookup. That is, either the class name:

parr = &Base<T>::arr[0];

or just with this:

parr = &this->arr[0];

Simple way to reference member variables of base class templates

As the solutions, you have to make the name value dependent to make it visible for name lookup. Besides the one you've showed, you can also:

  1. Use using to introduce the name,

    template<typename T>
    struct D1: B1<T> {
    using B1<T>::value; // or move it in method's scope according to your intent
    D1() {
    value = 1; // OK.
    }
    };
  2. Qualify with this->.

    template<typename T>
    struct D1: B1<T> {
    D1() {
    this->value = 1; // OK.
    }
    };

variable not detected in a templated nested and inherited class

You need to say this->bounds or Octree<U, T, _Prd>::bounds. In C++, when a class template inherits from another class template, the template base class is not instantiated during the first compilation pass, so the inherited members must be accessed with an explicit qualifier.

See this answer for a more elaborate explanation.

inheriting from a template class: member was not declared at this scope

If you use a name in a way that doesn't reference the template parameter visually, it should absolutely not depend on the template parameter!

void foo();

template <typename T>
struct A : T {
void bar() {
foo();
}
};

It could be very bad that if T has a foo member function then the call resolves to the member and not to the global function.

If there is no global foo you could argue that it could resolve to a member function/data member as fallback, but that would complicate the language and could be confusing to get right ("I want to call member foobar but I didn't realize that there was a global function that happens to have the right signature").

In your example someone could specialize A with no member data member. Would a hypothetical global member variable be used instead? With this-> it's unambiguous.



Related Topics



Leave a reply



Submit