Why would some compilers insist on qualifying members public members of template base class while the not requiring the same for non-template class? Please look at the following code listings:
Template class:
#include <iostream>
using namespace std;
template <class T>
class TestImpl {
public: // It wont make a difference even if we use a protected access specifier here
size_t vval_;
TestImpl(size_t val = 0) : vval_(val) { }
};
template <class T>
class Test : public TestImpl<T> {
public:
Test(size_t val) : TestImpl<T>(val) {
cout << "vval_ : " << vval_ << endl; // Error: vval_ was not declared in this scope
//! cout << "vval_ : " << TestImpl<T>::vval_ << endl; // this works, obviously
}
};
int main() {
Test<int> test1(7);
return 0;
}
Non-template class:
#include <iostream>
using namespace std;
class TestImpl {
public: // It wont make a difference even if we use a protected access specifier here
TestImpl(size_t val = 0) : vval_(val) {}
size_t vval_;
};
class Test : public TestImpl {
public:
Test(size_t val) : TestImpl(val) {
cout << "vval_ : " << vval_ << endl;
}
};
int main() {
Test test1(7);
return 0;
}
The significant difference between the above code listings is that while the first listing uses template classes, the second one doesn’t.
Now, both listings will compile fine with Microsoft’s Visual Studio Compiler (cl) but the first listing WONT compile with both the Digital Mars Compiler (dmc) and Minimalist GNU for Windows (MinGW – g++) compiler. I will get an error like “vval_ was not declared in the scope” – an error I obviously understand what it means.
If I qualify access to the TestImpl‘s public variable vval_ using TestImpl<T>::vval_ the code works. In the second listing, the compilers do not complain when the derived class accesses the base class’ vval_ variable without qualifying it.
With regard to the two compilers and possibly others, my question would be why I should be able to directly access (without qualifying) vval_ variable directly from a non-template class inheriting from a non-template class, while I cant do the same from a template class inheriting from a template class?
The problem you are facing is that for the compiler
vval_is not a dependent name, so it will try to look it up before the actual instantiation of the template with the type. At that point, the base type is not yet known to the compiler [*], and thus it does not consider the templated bases. Visual Studio does not perform the two phase lookup, and thus this is not required there.The solution is transforming the identifier into a dependent identifier, which can be done in one of multiple ways. The simplest and recommended would be using
this(as inthis->vval_). By adding the explicitthis, the compiler knows thatvval_can differ depending on the template arguments, it is now a dependent name, and it postpones lookup to the second phase (after argument substitution).Alternatively, you can qualify the type that the identifier belongs to, as @mrozenau suggests, by using
TestImpl<T>::vval_. Again that makes the identifier dependent on the template argumentTand lookup is postponed. While both of them serve the ultimate purpose of postponing the lookup to a later time, this second approach has the extra side effect that dynamic dispatch will be disabled. In this particular case it does not matter, but ifvval_was actually a virtual function thenthis->f()would call the final overrider, whileTestImpl<T>::f()would execute the overrider present inTestImpl<T>.[*] During the first phase verification of templates, before the arguments are substituted into the template, the base type is not yet known. The reason for this is that different sets of arguments might trigger the selection of different specializations of the base template.