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.
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
template base class typedef members invisible
You probably want to do:
using MemberType = typename TBase<T>::MemberType; // new type alias syntax
or
typedef typename TBase<T>::MemberType MemberType; // old type alias syntax
The syntax using Base::member;
can only be used to bring the declarations of non-type members into scope.
Also note that none of these are actually required, you can qualify each use (for types with the base, for non-types with either this->
or the base) and that will make the symbol dependent.
Related Topics
C++ Lambdas How to Capture Variadic Parameter Pack from the Upper Scope
How to Determine the Size of an Object in C++
Pointer-To-Pointer Dynamic Two-Dimensional Array
How to Get the Real and Total Length of Char * (Char Array)
What Is Data Alignment? Why and When Should I Be Worried When Typecasting Pointers in C
How to Identify the File Content as Ascii or Binary
When to Use Std::Begin and Std::End Instead of Container Specific Versions
What Are the Use Cases for Having a Function Return by Const Value for Non-Builtin Type
How Much Footprint Does C++ Exception Handling Add
How to Construct a Std::String from a Std::Vector<Char>
C++ Compile Time Error: Expected Identifier Before Numeric Constant
Initialization: Parenthesis VS. Equals Sign
How to Make Visual Studio Use the Native Amd64 Toolchain
C++ Inheritance - Inaccessible Base
Sorting a Std::Vector<Std::Pair<Std::String,Bool>> by the String
Why Does Std::Map Operator[] Create an Object If the Key Doesn't Exist