3

When deriving from a template base class, methods and attributes of the base class aren't immediately available, i.e if Base<T> has a void Func(), then Derived deriving from Base<T> has to call Base<T>::Func and not merely Func.

In Why must we specify template arguments for template base class when calling its constructor?, the following explanation is provided:

Injected class name are in the scope of the class. So are class member names. The general rule is that dependent base scope names are not visible at the point of definition of the derived template class. It is true that whatever T the injected class name of Base<T> is Base so compilers could infer that Base designate the injected class name of Base<T>. But that would be an other special rule. My opinion is that the c++ language has enough corner cases, and special rules which hurts coherency. So I am glad to see there is no special treatment for dependent base class injected name. - Oliv

In CppCon 2020 Back to Basics: Templates (part 1 of 2), the subject is touched upon as well and explained with

The simple nature of that is that because there is not necessarily only one of these [Base], you can publicly or privately derive multiple times from Foo just with a different type [...]

Oliv's one explains well why we can't call Base::Func, but if it also explains why we couldn't call Func, that's not clear to me.

As for the explanation by the CppCon presenter, sure, we could derive from multiple Base instantiations, but we don't. If A and B both have a void Func(), then if I derive from A, I can call Func without specifying A::Func. Only when I derive from A and B will the compiler understandably complain if I try to call Func. I would expect the same behaviour for templates: only when we derive from Base<T> and Base<U> would we get an ambiguity error. Or from A and Base<T> for that matter.

Is there a reason for things not be this way that I'm not seeing there ?

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Julien BERNARD
  • 653
  • 6
  • 17
  • 2
    One issue is that templates can be specialized. The compiler can't know what members of `Base` exist until it knows what `T` is and can instantiate the specialization for `T`. It is possible that `Base` and `Base` have no members in common. – NathanOliver Oct 22 '21 at 12:06
  • `this->Func` would also work, and behave as you expected (i.e. as the non-template case) for multiple bases. – Jarod42 Oct 22 '21 at 12:12
  • 1
    OT: Please note that in C++, we don't speak about "methods" and "attributes", but rather about "member functions" and "member variables". Though most people will likely understand what you meant, it is good practice to stick with the (by-standard) adopted terminology. Also, there are "attributes" in C++ as well, but they constitute a very different language mechanism. – Daniel Langr Oct 22 '21 at 12:17
  • 1
    Does this answer your question? [Why does the C++ standard specify that unqualified names in a template are non-dependent?](https://stackoverflow.com/q/42961940/817643) – StoryTeller - Unslander Monica Oct 22 '21 at 12:21
  • It does @StoryTeller-UnslanderMonica. Hadn't found this Q&A. Thanks ! Although now I wonder: why does this->Func() work, then ? – Julien BERNARD Oct 22 '21 at 12:27
  • 2
    @JulienBERNARD It works because `this` makes `Func` a dependent name, so it defers the lookup until the class is instantiated, and only then will you get compiler error if the member does not exist. – NathanOliver Oct 22 '21 at 12:30
  • `this->` cannot resolve to a name at namespace scope. So it either works or is ill-formed. If unqualified lookup could resolve differently per specialisation it would do so in a completely silent manner. Silent behavior changes are a land mine. That's why templates are so constrained. – StoryTeller - Unslander Monica Oct 22 '21 at 12:32

0 Answers0