Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does inheriting constructors work with templates in C++0x?

Tags:

In C++0x, you can use the using keyword to inherit constructors, like so:

class B { B(int) {} };  class A : public B { using B::B; }; 

Which will implicitly declare an A(int) constructor. Does this work with templates?

class B { B(int) {} };  template<class T> class A : public T { using T::T; }; 

Within T::T, I expect the compiler to figure out the left hand T since using the scope operator on template arguments is normal, but figuring out that the right hand T is the constructor is a special case. In fact it appears there's an ambiguity: what if I have a method called T in B that I'm trying to add overloads to in A (that's how a compiler would interpret such a using declaration pre-C++0x)?

like image 437
Joseph Garvin Avatar asked Sep 12 '11 21:09

Joseph Garvin


People also ask

Can template class inherit?

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.

Can you inherit constructors?

No, constructors cannot be inherited in Java. In inheritance sub class inherits the members of a super class except constructors. In other words, constructors cannot be inherited in Java therefore, there is no need to write final before constructors.

Is inheritance better than templates?

Templates provide sortability in a much nicer way, since the sortee doesn't need to know that it's being sorted. Complex inheritance typically results when you work with a forced mindset that everything must be an inheritance hierarchy, which is in fact rarely appropriate.

Is it possible to inherit the constructors of its base class?

In inheritance, the derived class inherits all the members(fields, methods) of the base class, but derived class cannot inherit the constructor of the base class because constructors are not the members of the class.


1 Answers

Yes it works, and the reason is the name lookup mechanism. The mechanism a inheriting-constructors declaration works is simple: If the using declaration's name refers to base class constructors, that's an inheriting constructors declaration. At 3.4.3.1[class.qual]p2 we find:

In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C

  • if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9), or
  • in a using-declaration (7.3.3) that is a member-declaration, if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id's template-name in the last component of the nested-name-specifier

the name is instead considered to name the constructor of class C.

This is the paragraph that makes out of class constructor definitions work, and this is also the paragraph that makes inheriting constructor declarations work. The second bullet applies in this case:

struct B {   B(int) { } };  typedef B mytype;  struct A : B {   // "name ... is the same as the identifier ... in the last component ..."   using mytype::mytype; };   template<typename T> using same = T;  struct C : B {   // "name ... is the same as the template-name ... in the last component ..."   same<B>::same; }; 

The latter example proves also useful in cases such as the following

template<template<typename> class Base> struct X : Base<int> {   using Base<int>::Base; }; 

In summary:

  • The first bullet above is a semantic rule - if the name after the nested name specifier refers to the injected class name (B::B or mytype::B), then it will be translated to refer to the constructor(s).

  • The second bullet is a syntactic rule - the names just must match - their meaning is irrelevant otherwise - there could have been a member called Base in the template argument provided to X, such as in the following, but the using declaration would still import the constructors and do not name the member Base:

    template<typename T> struct D { private: T Base; }; X<D> x; // valid, the private member is *not* touched! 
like image 134
Johannes Schaub - litb Avatar answered Nov 26 '22 13:11

Johannes Schaub - litb