US-65: Removing Inheriting Constructors

Author: Douglas Gregor
Contact: doug.gregor@gmail.com
Organization: Apple
Date: 2011-02-28
Number: N3258=11-0028

Introduction

This proposal recommends the removal of inheriting constructors (N2540) from the C++0x working paper, per National Body comment US-65. The author believes that inheriting constructors should be considered as a feature for future language standards, but that the risks associated with keeping this feature in the C++0x working paper far outweigh the benefits.

Inheriting constructors should be removed from the C++0x working paper for the following reasons:

Emulating Inheriting Constructors with Variadic Templates

One can emulate inheriting constructors using a catch-all variadic template that forwards all of its arguments. For example:

template<typename Mixin>
class add_color : public Mixin {
  Color color;

public:
  template<typename ...Args>
  add_color(Args &&...args)
    : Mixin(std::forward<Args>(args)...), color(Red) { }
};

There are several benefits to the variadic-template implementation for constructor forwarding:

There are also several problems with the variadic-template implementation:

The variadic-template implementation is clearly not a drop-in replacement for inheriting constructors, and there are trade-offs in both directions. Does that mean we need both features? Perhaps, but we need usage experience to determine whether the inheriting-constructors feature as specified has the right design tradeoffs. We may find that the limitations of the feature as specified mean that the vast majority of users will end up employing the variadic-template implementation instead, in which case we'd likely want to change the design of inheriting constructors. We need this usage experience prior to standardization, not after standardization, and it becomes even more important when we already have a partial solution to the problem.

Proposed Wording

Modify 3.4.3.1 [class.qual]p2 as follows:

  1. In a lookup in which the constructor is an acceptable lookup result, and the nested-name-specifier nominates a class C: , and the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9), the name is instead considered to name the constructor of class C. [ Note: for example, the constructor is not an acceptable lookup result in an elaborated-type-specifier so the constructor would not be used in place of the injected-class-name. -- end note ] Such a constructor name shall be used only in the declarator-id of a declaration that names a constructor or in a using-declaration.

Modify 7.3.3 [namespace.udecl] as follows:

  1. A using-declaration introduces a name into the declarative region in which the using-declaration appears. That name is a synonym for the name of some entity declared elsewhere.
    using-declaration:
      using typenameopt ::opt nested-name-specifier unqualified-id ;
      using :: unqualified-id ;
    
    The member name specified in a using-declaration is declared in the declarative region in which the using- declaration appears. [Note: only the specified name is so declared; specifying an enumeration name in a using-declaration does not declare its enumerators in the using-declaration's declarative region. -- end note] If a using-declaration names a constructor (3.4.3.1), it implicitly declares a set of constructors in the class in which the using-declaration appears (12.9); otherwise the name specified in a using-declaration is a synonym for the name of some entity declared elsewhere.
  2. (No change to this paragraph)
  3. In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined. If such a using-declaration names a constructor, the nested-name-specifier shall name a direct base class of the class being defined; otherwise itSuch a using-declaration introduces the set of declarations found by member name lookup (10.2, 3.4.3.1).
  4. [Note: Since constructors and destructors do not have names, a using-declaration cannot refer to a constructor or destructor for a base class. Since specializations of member templates for conversion functions are not found by name lookup, they are not considered when a using-declaration specifies a conversion function (14.5.2). -- end note ]
  1. When a using-declaration brings names from a base class into a derived class scope, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting). [ Note: For using-declarations that name a constructor, see 12.9. -- end note ]
  2. (No change to this paragraph)
  3. The access rules for inheriting constructors are specified in 12.9; otherwise allAll instances of the name mentioned in a using-declaration shall be accessible. In particular, if a derived class uses a using-declaration to access a member of a base class, the member name shall be accessible. If the name is that of an overloaded member function, then all functions named shall be accessible. [...]
  4. The alias created by the using-declaration has the usual accessibility for a member-declaration. [Note: A using-declaration that names a constructor does not create aliases; see 12.9 for the pertinent accessibility rules. -- end note]

Remove section 12.9 [class.inhctor].

Note: we leave the change to 12.1 [class.ctor]p5, which was a small clarification that does not have anything to do with inheriting constructors.


Last modified: Mon Feb 28 08:34:59 PST 2011