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];
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
Derived template-class access to base-class member-data
You can use this->
to make clear that you are referring to a member of the class:
void Bar<T>::BarFunc () {
std::cout << this->_foo_arg << std::endl;
}
Alternatively you can also use "using
" in the method:
void Bar<T>::BarFunc () {
using Bar<T>::_foo_arg; // Might not work in g++, IIRC
std::cout << _foo_arg << std::endl;
}
This makes it clear to the compiler that the member name depends on the template parameters so that it searches for the definition of that name in the right places. For more information also see this entry in the C++ Faq Lite.
Access to protected member variable from derived inner class in a templated parent class
You can use a using
declaration.
template <typename T>
struct Temp
{
struct BaseIterator
{
protected:
int pos;
BaseIterator() : pos(0) {}
};
struct LeafIterator : public BaseIterator
{
using BaseIterator::pos;
int * operator * () { return &pos; }
LeafIterator() : BaseIterator() {}
};
};
int main()
{
Temp<int>::LeafIterator leaf_iterator;
}
This compiles fine in GCC 8.2.0.
access static member of template parent class
The compiler does not resolve the inherited members for template base classes, due to the fact that you may have specializations that do not define the member, and in that case the whole parsing/name resolving business will become quite difficult.
If your member is non-static, then using this->n_parent
"assures" the compiler that n_parent
is indeed a member of the base class. If the member is static
, there is no this
pointer (as you mention), so the only choice is to qualify the base class as you do.
Related: Derived template-class access to base-class member-data
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.
Related Topics
Why Not Infer Template Parameter from Constructor
C/C++: Force Bit Field Order and Alignment
Catching Access Violation Exceptions
When Were the 'And' and 'Or' Alternative Tokens Introduced in C++
Best Way to Store Currency Values in C++
Rounding Up to the Nearest Multiple of a Number
Why Does Pointer Decay Take Priority Over a Deduced Template
Setting the Internal Buffer Used by a Standard Stream (Pubsetbuf)
C++: Catch a Divide by Zero Error
Remove Elements of a Vector Inside the Loop
Create N-Element Constexpr Array in C++11
Unresolved External Symbol in Object Files
How to Pass a Member Function Pointer