Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template base class accessible when inheriting from a specific specialization?

The other day, I discovered that this was possible:

template <class T> struct base {};
struct derived: base<int> {};

int main()
{
    // The base class template is accessible here
    typename derived::base<double> x;

    // from the comments, even this works
    typename derived::derived::base<double>::base<int>::base<void> y;
}

I have no recollection of ever reading this on cppreference or in C++ tutorials, or this being exploited in clever template metaprogramming tricks (because I'm sure it can be). I have several questions:

  • Does this thing have a specific name?
  • Where is it documented in the C++ standard and on cppreference?
  • Is there any template metaprogramming trick exploiting this?
like image 240
Vincent Avatar asked Jan 15 '18 18:01

Vincent


People also ask

Can a class inherit from a 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.

How class templates can be used with inheritance?

Class Template Inheritance in C++ If we need the new derived class to be general, we must make it a template class with a template argument sent to the base class. This is because inheritance is only possible with a class, and a template is not a class unless it is instantiated by passing some data type to it.

What are the thing inherited from the base class?

The class whose members are inherited is called the base class, and the class that inherits those members is called the derived class. A derived class can have only one direct base class. However, inheritance is transitive.

How do I access template classes?

Accessing template base class members in C++ In order to access a member (method or field) of a templated base class, you need to either use the “this” pointer or use the explicit name of the base class with template arguments. without “this->” in front of “this->x”, it would not be able to find the member.


1 Answers

As pointed out by @Nir Friedman in comment, typename derived::derived::base<double>::base<int>::base<void> y; might actually be ill-formed because derived::derived::base<double>::base<int>::base is treated as a constructor of base, per [class.qual]/2.


  • Does this thing have a specific name?

It is called injected-class-name.

  • Where is it documented in the C++ standard and on cppreference?

In the standard: [class]/2 specifies that the name of a class is treated as if it were a public member of that class. [temp.local] specifies that the injected-class-name of a class template can be used as either a template-name or a type-name.

On cppreference: it is (incompletely) documented in http://en.cppreference.com/w/cpp/language/unqualified_lookup#Injected_class_name.

  • Is there any template metaprogramming trick exploiting this?

I'm not aware of any such tricks, though in everyday use, injected-class-name is employed whenever the current class is named in the class definition:

template<class T>
struct A {
    A<T>& operator=(const A<T>&); // injected-class-name as template-name
    A& operator=(A&&); // injected-class-name as type-name
};

The latter may be deliberately used to shorten member declaration.

The injected-class-name of a base class is mostly used (unconsciously) in a member initializer list:

struct B : A<int> {
    B() : A() {}
};
like image 51
cpplearner Avatar answered Sep 20 '22 03:09

cpplearner