Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why when a template class inherits from another template class, typedefs need to be respecified and functions calls qualified?

When a template class inherits from another template class, typedefs in the base class must be redefined again (i.e. they are not automatically inherited), and function calls in the base class need to be qualified. Why is that? Isn't this already unambiguous?

So if I have 20 template classes, all defining the same typedefs, I am not able to introduce a base class containing these definitions them and inherit from it, as I have to redefine the typedefs anyway in every class, which defeats the purpose. This is makes the source code so unnecessarily verbose.

I can see this has been discussed in this question, but I do not understand the comment

The C++ name lookup rules specify that a name is only searched in a templated base classes if it depends on a template parameter (if it is a "dependent name"). If a name does not depend on a template parameter it isn't searched there.

What is the reason for this? It makes no sense to me.

Perhaps, the following code snippet would illustrate my question better:

#include <iostream>

template <unsigned N, typename T>
struct A
{
   typedef T U;
   static void foo(T x) { std::cout << N + x << "\n"; }
};

template <unsigned N, typename T>
struct B : public A<N, T>
{
    // Why do I have to redeclare U? Isn't is unambiguous already?
    typedef typename A<N, T>::U U;

    //  why do I have to specify B::? Isn't it unambiguous already?
    static void zoo(U x) { B::foo(x); }  
};

int main()
{
    B<2,int>().zoo(3);
    B<2,double>().zoo(3.5);
    return 0;
}
like image 905
Fabio Avatar asked Jan 11 '18 04:01

Fabio


People also ask

Can a template class inherit from another template class?

Inheriting from a template classIt is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

When class is there why do we need template?

What are Class Templates in C++? Templates are the mechanism by which C++ implements the generic concept. Simply, they allow you to pass data type as a parameter so that you don't need to write the same code for different data types.

What is the difference between class and Typename in template?

There is no difference between using <typename T> OR <class T> ; i.e. it is a convention used by C++ programmers.

What is the difference between a template class and class template in C++?

An individual class defines how a group of objects can be constructed, while a class template defines how a group of classes can be generated. Note the distinction between the terms class template and template class: Class template. is a template used to generate template classes.


2 Answers

That's happening because of two phase lookup. Quote from here:

  1. Template definition time: when the template is initially parsed, long before it is instantiated, the compiler parses the template and looks up any "non-dependent" names. A name is "non-dependent" if the results of name lookup do not depend on any template parameters, and therefore will be the same from one template instantiation to another.
  2. Template instantiation time: when the template is instantiated, the compiler looks up any "dependent" names, now that it has the full set of template arguments to perform lookup. The results of this lookup can (and often do!) vary from one template instantiation to another.

So, during initial parsing compiler thinks that U is non-dependent name and tries to look it up and it can't find anything because it isn't allowed to look into the dependent base class. But if U were dependent name then compiler would look it up during instantiation phase and would find it in the base class.

BTW: VS will readily compile this, but they have added possibility of two phase lookup lately.

like image 146
Yola Avatar answered Oct 18 '22 19:10

Yola


The fundamental reason is that classes can be specialized:

template<class T>
struct A {};

template<class T>
struct B : A<T> {
  typedef typename A<T>::referent target;
  void niceName() {A<T>::uglyName();}
};

template<class T>
struct A<T*> {
  typedef T referent;
  void uglyName();
};

B<int*>::target i;  // OK: int

Of course, the reverse case (where the primary template defines useful things, and we simply fear that a specialization might change or remove them) is more common, which makes the rule seem arbitrary.

like image 30
Davis Herring Avatar answered Oct 18 '22 20:10

Davis Herring