Template Classes vs Private Inheritance

Why do some compilers insist on qualifying members of the public members of the base class of the template, rather than requiring the same for a class without a template? Please review the following code lists:

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; } 

Class without template:

 #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 lists is that while the first list uses the template classes, the second does not.

Both lists will now be compiled using the Microsoft Visual Studio Compiler (cl), but the first WONT list has been compiled with both the Digital Mars Compiler (dmc) and GNU Minimalist for Windows (MinGW - g ++). I will get an error, for example, "vval_ has not been declared in the scope" - an error that I obviously understand what this means.

If I access the public variable TestImpl vval _ using TestImpl <T> :: vval _ , the code works. In the second listing, compilers do not complain when the derived class accesses the vval _ base class variable without assigning it.

As for the two compilers, and possibly others, my question will be why should I be able to directly access (without qualification) the variable vval _ directly from the non-template class, inheriting from the class without the template , while I can't do the same from the template class inheriting from the template class ?

+3
c ++ inheritance oop
source share
3 answers

The problem you are facing is that for the compiler, vval_ not a dependent name, so it will try to find it before actually creating a template with a type. At this moment, the base type is not yet known to the compiler [*] and therefore it does not consider template databases. Visual Studio does not perform a two-phase search, and therefore this is not required here.

The solution converts the identifier into a dependent identifier, which can be performed in one of several ways. The easiest way is to use this (as in this->vval_ ). By adding an explicit this , the compiler knows that vval_ may differ depending on the arguments of the template, now it is a dependent name and delays the search to the second phase (after replacing the argument).

Alternatively, you can determine the type to which the identifier belongs, as @mrozenau suggests, using TestImpl<T>::vval_ . Again, this identifier depends on the template argument T , and the search is delayed. Although both serve the ultimate goal of delaying the search until a later time, this second approach has an additional side effect that dynamic submission will be turned off. In this particular case, it does not matter, but if vval_ actually a virtual function, then this->f() will call the final redirector, and TestImpl<T>::f() will perform the override present in TestImpl<T> .

[*] During the first phase of checking templates before changing arguments to the template, the base type is not yet known. The reason for this is that different sets of arguments can trigger the selection of different specializations of the base template.

+2
source share

You need to qualify vval_ with TestImpl<T> to tell the compiler that it depends on the actual type T in Test<T> (there may be some partial / explicit TestImpl<T> specializations declared before the definition of Test<T> and its creation which will change the value of vval_ in this context, so that the compiler knows about it, you must say that vval_ (template parameter) is dependent.

See also http://gcc.gnu.org/onlinedocs/gcc/Name-lookup.html

+6
source share

MSVC (Microsoft ...) has never been standard when it comes to template code, so it's odd :)

The problem is that the patterns are analyzed in two phases:

  • The first phase is performed during the analysis of the template, and any identifier that does not (explicitly) depend on the template parameters should be allowed.
  • The second phase is executed when the pattern is instanciated

In your case, the first phase fails because vval_ does not explicitly depend on the template parameter (it is not a dependent name), so it must be available.

A simple means is to qualify vval_ , usually with this-> , to mark it as dependent.

+3
source share

All Articles