<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>N4429: Rewording inheriting constructors (core issue 1941 et al)</title>

<style type="text/css">
  ins, ins > * { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  del, del > * { text-decoration:line-through; background-color:#FFA0A0 }
  .ins { background-color:#C0FFC0 }
</style>

</head>

<body>
<div style="text-align: right; float: right">
ISO/IEC JTC1 SC22 WG21<br>
P0136R0<br>
Revises: N4429<br>
Richard Smith<br>
richard@metafoo.co.uk<br>
2015-09-25<br>
</div>

<h1>Rewording inheriting constructors (core issue 1941 et al)</h1>

<p>Fixing:</p>
<b><ul>
<li><a href="wg21.link/cwg1573">Core Issue 1573</a>: Inherited constructor characteristics
<li><a href="wg21.link/cwg1645">Core Issue 1645</a>: Identical inheriting constructors via default arguments
<li><a href="wg21.link/cwg1715">Core Issue 1715</a>: Access and inherited constructor templates
<li><a href="wg21.link/cwg1736">Core Issue 1736</a>: Inheriting constructor templates in a local class
<li><a href="wg21.link/cwg1903">Core Issue 1903</a>: What declarations are introduced by a non-member using-declaration?
<li><a href="wg21.link/cwg1941">Core Issue 1941</a>: SFINAE and inherited constructor default arguments
<li><a href="wg21.link/cwg1959">Core Issue 1959</a>: Inadvertently inherited copy constructor
<li><a href="wg21.link/cwg1991">Core Issue 1991</a>: Inheriting constructors vs default arguments
</ul></b>

<h2>Changes since N4429</h2>

<ul>
  <li>in 7.3.3p15, don't restrict the set of inherited members</li>
  <li>in 7.3.3.p17, make explicit that no access check is performed in "<tt>using Base::Base;</tt>"</li>
  <li>in 7.3.3.p18, make it clearer that the accessibility of the base class is not considered when using a constructor inherited from a base class</li>
  <li>in 12.6.3.p1, make it clearer that we don't default-initialize the chosen base class</li>
  <li>in 12.6.3.p2, give a more complex example showing the Y != X case</li>
  <li>in 12.6.3, directly initialize the class from which the constructor was originally inherited rather than proceeding recursively, and clarify that parameter initialization is sequenced before subobject initialization</li>
</ul>

<h2>Overview</h2>

<p>
There are a number of active core issues relating to inheriting constructors,
with a single common theme: an inheriting constructor does not act like any
other form of <em>using-declaration</em>. The reason for this is that all other
<em>using-declaration</em>s make some set of declarations visible to name lookup
in another context, but an inheriting constructor declaration declares a new
constructor (or set thereof) that merely delegates to the original.

<p>
After some discussion in CWG, it is believed that these issues can all be
resolved by changing the meaning of an inheriting constructor declaration from
declaring a set of new constructors, to making a set of base class constructors
visible in a derived class <em>as if</em> they were derived class constructors.
(When such a constructor is used, the additional derived class subobjects will
also be implicitly constructed as if by a defaulted default constructor.)
Put another way:
<strong>this proposal makes inheriting a constructor act just like
inheriting any other base class member, to the extent possible</strong>.

<p>
This change does affect the meaning and validity of some programs, but
these changes improve the consistency and comprehensibility of C++. CWG
wishes to treat this change as a DR against C++11.

<h2>Examples of behavior changes</h2>

<ul>
<li>SFINAE on inheriting constructors now works reliably
<pre>
struct A {
  template&lt;typename T> A(T, typename enable_if&lt;sizeof(T) == 4, int>::type = 0);
};
struct B : A {
  using A::A; // formerly declared
              //   #1: B(T)
              //   #2: B(T, typename enable_if&lt;...>::type)
              // now makes A::A(T, typename enable_if&lt;...>::type = 0)
              // visible as a constructor of B
  B(...);
};
B b(123ull);  // now ok; used to ignore SFINAE condition and select inherited constructor #1
</pre>

<li>Hiding works the same as for other member <em>using-declarations</em> in the presence of default arguments
<pre>
struct A {
  A(int a, int b = 0);
  void f(int a, int b = 0);
};
struct B : A {
  B(int a);      using A::A;
  void f(int a); using A::f;
};
struct C : A {
  C(int a, int b = 0);      using A::A;
  void f(int a, int b = 0); using A::f;
};

B b(0); // was ok, now ambiguous
b.f(0); // ambiguous (unchanged)

C c(0); // was ambiguous, now ok
c.f(0); // ok (unchanged)
</pre>

<li>Inheriting constructor parameters are no longer copied
<pre>
struct A { A(const A&amp;) = delete; A(int); };
struct B { B(A); void f(A); };
struct C : B { using B::B; using B::f; };
C c({0}); // was ill-formed, now ok (no copy made)
c.f({0}); // ok (unchanged)
</pre>

<li>Ellipsis parameters used to be unimplementable on some ABIs
<pre>
struct A { A(const char *, ...); };
struct B : A { using A::A; };
B b("%d %d", 1, 2); // ok, now implementable
</pre>

<li>Access check now exactly matches the base class member
<pre>
class A {
public:
  template&lt;typename T> A(T, typename T::type);
private:
  A(int);
  friend void f();
};
class B {
  typedef int type;
  friend class A;
};
struct C : A {
  using A::A;
};

void f() {
  A a1(B(), 0); // ok (unchanged)
  C c1(B(), 0); // was ill-formed (implicit C constructor can't access B::type), now ok

  A a2(42); // ok (unchanged, f is a friend)
  C c2(42); // was ill-formed (implicit C constructor can't access A constructor), now ok
}
C c3(123); // still ill-formed, no access to A(int) constructor
</pre>
This access behavior differs from that of a normal member
<em>using-declaration</em>,
but matches the existing design of inheriting constructors.
</ul>

<h2>Proposed wording</h2>

<p>
Remove 12.9 class.inhctor, "Inheriting constructors".
</p>

<p>
Change in 3.9 basic.types paragraph 10:
</p>
<blockquote>
A type is a <em>literal type</em> if it is:
<ul><li>&hellip;
    <li>a class type (Clause 9) that has all of the following properties:
      <ul><li>&hellip;
          <li>it is an aggregate type (8.5.1) or has <ins>or inherits (7.3.3)</ins>
              at least one <tt>constexpr</tt> constructor or constructor template
              that is not a copy or move constructor, and
          <li> &hellip;
      </ul>
</ul>
</blockquote>

<p>
Change in 7.1.5 dcl.constexpr paragraph 5:
</p>
<blockquote>
For a <del>non-template, non-defaulted</del> constexpr function or <del>a non-template, non-defaulted, non-inheriting</del>
constexpr constructor <ins>that is neither defaulted nor a template</ins>, if no argument values exist such that &hellip;
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 1:
</p>
<blockquote>
A <i>using-declaration</i> introduces a
<del>name</del><ins>set of declarations</ins>
into the declarative region
in which the <i>using-declaration</i> appears.

<pre>
<i>using-declaration</i>:
    using typename<sub>opt</sub> <i>nested-name-specifier unqualified-id</i> ;
</pre>

<ins>
The set of declarations introduced by the <i>using-declaration</i> is found
by performing qualified name lookup (3.4.3, 10.2) for the name in the <i>using-declaration</i>,
excluding functions that are hidden as described below.
If the <i>using-declaration</i> does not name a constructor, the <i>unqualified-id</i>
</ins>
<del>
The member name specified in a <i>using-declaration</i>
</del>
is declared in the declarative region
in which the <i>using-declaration</i> appears
<del>
.
[ Note:
Only the specified name is so declared;
specifying an enumeration name in a <i>using-declaration</i>
does not declare its enumerators in the <i>using-declaration</i>'s declarative region.
&mdash; end note ]

If a <i>using-declaration</i> 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
</del>
<ins>as</ins>
a synonym for <del>a</del><ins>the</ins> set of declarations
<ins>introduced by the <i>using-declaration</i></ins>
<del>in another namespace or class</del>.
<ins>
[ Note:
Only the specified name is so declared;
specifying an enumeration name in a <i>using-declaration</i>
does not declare its enumerators in the <i>using-declaration</i>'s declarative region.
&mdash; end note ]
</ins>
<ins>If the <i>using-declaration</i> names a constructor, it declares that the
class <em>inherits</em> the set of constructor declarations introduced
by the <i>using-declaration</i> from the nominated base class.</ins>
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 3:
</p>
<blockquote>
In a <i>using-declaration</i> used as a <i>member-declaration</i>, the <i>nested-name-specifier</i> shall name a base class of the
class being defined. If such a <i>using-declaration</i> names a constructor, the <i>nested-name-specifier</i> shall name a
direct base class of the class being defined<del>; otherwise it introduces the set of declarations found by member
name lookup (10.2, 3.4.3.1)</del>. [ Example ]
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 4:
</p>
<blockquote>
[ Note ]
If <del>an</del><ins> a constructor or</ins> assignment operator brought from a
base class into a derived class <del>scope</del> has the signature of a copy/move
<ins>constructor or</ins> assignment operator for the derived class (12.8),
the <i>using-declaration</i> does not by itself suppress the implicit
declaration of the derived class <del>assignment operator</del><ins>member</ins>;
the <del>copy/move assignment operator</del><ins>member</ins>
from the base class is hidden or overridden by the implicitly-declared
copy/move <ins>constructor or</ins> assignment operator of the derived class,
as described below.
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 8:
</p>
<blockquote>
A <i>using-declaration</i> <del>for</del><ins>that names</ins> a class member shall be a <i>member-declaration</i>. [ Example ]
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 11:
</p>
<blockquote>
<ins>[ Note:</ins>
For a <i>using-declaration</i> that names a namespace,</ins>
members added to the namespace after the <i>using-declaration</i> are not <ins>in the set of introduced declarations,
so they are not</ins> considered when a use of the name is made.
<del>[ Note:</del>
Thus, additional overloads &hellip;
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 15:
</p>
<blockquote>
When a <i>using-declaration</i> brings <del>names</del><ins>declarations</ins>
from a base class into a derived class <del>scope</del>,
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 <i>ref-qualifier</i> (if any)
in a base class (rather than conflicting).
<ins>Such hidden or overridden declarations are excluded from the set of declarations introduced
by the <i>using-declaration</i>.</ins>
<del>[ Note: For using-declarations that name a constructor, see 12.9. &mdash; end note ]</del>
[ Example:
<pre>
struct B {
&hellip;
}
<ins>
struct B1 {
  B1(int);
};

struct B2 {
  B2(int);
};

struct D1 : B1, B2 {
  using B1::B1;
  using B2::B2;
};
D1 d1(0);    // ill-formed: ambiguous

struct D2 : B1, B2 {
  using B1::B1;
  using B2::B2;
  D2(int);   // OK: D2::D2(int) hides B1::B1(int) and B2::B2(int)
};
D2 d2(0);    // calls D2::D2(int)
</pre>
]
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 16:
</p>
<blockquote>
For the purpose of overload resolution, the functions
<del>which</del><ins>that</ins> are introduced by a <i>using-declaration</i> into a
derived class <del>will be</del><ins>are</ins> treated as though they were members of the derived class. In particular, the implicit
<tt>this</tt> parameter shall be treated as if it were a pointer to the derived class rather than to the base class.
This has no effect on the type of the function, and in all other respects the function remains a member of
the base class.
<ins>Likewise, constructors that are introduced by a <i>using-declaration</i> are
treated as though they were constructors of the derived class when looking up the
constructors of the derived class (3.4.3.1) or forming a set of
overload candidates (13.3.1.3, 13.3.1.4, 13.3.1.7). If such a constructor is selected
to perform the initialization of an object of class type, all subobjects other than
the base class from which the constructor originated are implicitly initialized
([class.inhctor.init]).</ins>
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 17:
</p>
<blockquote>
<ins>In a <i>using-declaration</i> that does not name a constructor,
all members of the set of introduced declarations</ins>
<del>The access rules for inheriting constructors are specified in 12.9;
otherwise all instances of the name mentioned in
a <i>using-declaration</i></del> shall be accessible.
<ins>In a <i>using-declaration</i> that names a constructor,
no access check is performed.</ins>
&hellip;
</blockquote>

<p>
Change in 7.3.3 namespace.udecl paragraph 18:
</p>
<blockquote>
<del>The alias</del><ins>A synonym</ins> created by <del>the</del><ins>a</ins> <i>using-declaration</i>
has the usual accessibility for a <i>member-declaration</i>.
<del>
[ Note:
</del>
A <i>using-declaration</i> that names a constructor does not create <del>aliases; see 12.9 for the pertinent accessibility
  rules. — end note ]</del> <ins>a synonym; instead, the additional constructors are
accessible if they would be accessible when used to construct an object of the
corresponding base class, and the accessibility of the <i>using-declaration</i> is ignored.</ins>
[ Example ]
</blockquote>

<p>
Change in 9.2 class.mem paragraph 2:
</p>
<blockquote>
A class is considered a completely-defined object type (3.9) (or complete type) at the closing <tt>}</tt> of the
<i>class-specifier</i>.
Within the class <i>member-specification</i>, the class is regarded as complete within function bodies,
default arguments, <del><i>using-declaration</i>s introducing inheriting constructors (12.9),</del>
<i>exception-specification</i>s,
and <i>brace-or-equal-initializer</i>s for non-static data members
(including such things in nested classes).
Otherwise it is regarded as incomplete within its own class <i>member-specification</i>.
</blockquote>

<i>Drafting note: as observed in core issue 1487, it is not permitted to derive from an incomplete class, and the
  class is not regarded as complete within base-clauses, so this provision doesn't seem useful.</i>

<p>
Change in 10 class.derived paragraph 2:
</p>
<blockquote>
&hellip;
Unless redeclared in the derived class,
members of a base class are also considered to be members of the derived class.
<del>The</del>
<ins>Members of a</ins> base class<del> members</del><ins> other than constructors</ins>
are said to be <em>inherited</em> by the derived class.
<ins>Constructors of a base class can also be inherited as described in 7.3.3.</ins>
Inherited members can be referred to in expressions in the same manner
as other members of the derived class, unless their names are hidden or ambiguous (10.2).
&hellip;
</blockquote>

<p>
Add a new subclause after 12.6.2 class.base.init:
</p>
<blockquote class="ins">
<h3>12.6.3 Initialization by inherited constructor [class.inhctor.init]</h3>

<ol>
<li>

<p>
When a constructor for type <tt>B</tt> is invoked to initialize an object of
a different type <tt>D</tt> (that is, when the constructor was inherited (7.3.3)),
initialization proceeds as if a defaulted default constructor is used to initialize
the <tt>D</tt> object and each base class subobject from which the constructor was
inherited, except that the <tt>B</tt> subobject is initialized by the invocation
of the inherited constructor.
The complete initialization is considered to be a single function call; in
particular, the initialization of the inherited constructor's parameters is
sequenced before the initialization of any part of the <tt>D</tt> object.
[ Example:
<pre>
struct B1 {
  B1(int, ...) { }
};

struct B2 {
  B2(double) { }
};

int get();

struct D1 : B1 {
  using B1::B1;  // inherits B1(int, ...)
  int x;
  int y = get();
};

void test() {
  D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
                 // then d.x is default-initialized (no initialization is performed),
                 // then d.y is initialized by calling get()
  D1 e;          // error: D1 has no default constructor
}

struct D2 : B2 {
  using B2::B2;
  B1 b;
};

D2 f(1.0);       // error: B1 has no default constructor

struct W { W(int); };
struct X : virtual W { using W::W; X() = delete; };
struct Y : X { using X::X; };
struct Z : Y, virtual W { using Y::Y; };
Z z(0); // OK: initialization of Y does not invoke default constructor of X

template&lt;class T&gt; struct Log : T {
  using T::T;    // inherits all constructors from class T
  ~Log() { std::clog &lt;&lt; "Destroying wrapper" &lt;&lt; std::endl; }
};
</pre>
Class template <tt>Log</tt> wraps any class and forwards all of its constructors,
while writing a message to the standard log whenever an object of class
<tt>Log</tt> is destroyed.
]
</p>

<li>
<p>
If the constructor was inherited from multiple base class subobjects of type
<tt>X</tt>, the program is ill-formed.
[ Example:
<pre>
struct A { A(int); };
struct B : A { using A::A; };

struct C1 : B { using B::B; };
struct C2 : B { using B::B; };

struct D1 : C1, C2 {
  using C1::C1;
  using C2::C2;
};

struct V1 : virtual B { using B::B; };
struct V2 : virtual B { using B::B; };

struct D2 : V1, V2 {
  using V1::V1;
  using V2::V2;
};

D1 d1(0); // ill-formed: ambiguous
D2 d2(0); // OK: initializes virtual B base class, which initializes the A base class
          // then initializes the V1 and V2 base classes as if by a defaulted default constructor

struct M { M(); M(int); };
struct N : M { using M::M; };
struct O : M {};
struct P : N, O {};
P p(0); // OK: use M(0) to initialize N's base class,
        // use M() to initialize O's base class
</pre>
]
</p>

<em>Drafting note: This is intended to mirror the behavior when invoking a
non-static member function inherited from multiple base classes.</em>

<li>
<p>When an object is initialized by an inheriting constructor, the principal
constructor (12.6.2, 15.2) for the object is considered to have completed
execution when the initialization of all subobjects is complete.
</p>

</blockquote>

<p>
Do not change 15.2 except.ctor paragraph 3:
</p>
<blockquote>
For an object of class type of any storage duration whose initialization or destruction is terminated by an
exception, the destructor is invoked for each of the object's fully constructed subobjects, that is, for each
subobject for which the principal constructor (12.6.2) has completed execution
and the destructor has not yet begun execution,
except that in the case of destruction,
the variant members of a union-like class are not destroyed. &hellip;
</blockquote>

<p>
Change in 15.2 except.ctor paragraph 4:
</p>
<blockquote>
Similarly, if the <del>non-delegating</del><ins>principal</ins> constructor for an object has completed execution
and a delegating constructor for that object exits with an exception, the object's destructor is invoked. Such destruction is sequenced
before entering a handler of the function-try-block of a delegating constructor for that object, if any.
</blockquote>

<p>
Change in 15.4 except.spec paragraph 15:
<p>
<blockquote>
The <em>set of potential exceptions of an expression</em> <tt>e</tt>
is empty if <tt>e</tt> is a core constant expression (5.20).
Otherwise, it is the union of the sets of potential exceptions
of the immediate subexpressions of <tt>e</tt>,
including default argument expressions used in a function call,
combined with a set <em>S</em> defined by the form of <tt>e</tt>, as follows:

<ul>
<li>If <tt>e</tt> is a function call, &hellip;
<li>If <tt>e</tt> implicitly invokes a function &hellip;
<li><ins>If <tt>e</tt> initializes an object of type <tt>D</tt>
using an inherited constructor for a class of type <tt>B</tt> ([class.inhctor.init]),
<em>S</em> also contains
the sets of potential exceptions of
the implied constructor invocations for subobjects of <tt>D</tt>
that are not subobjects of <tt>B</tt>
(including default argument expressions used in such invocations)
as selected by overload resolution,
and
the sets of potential exceptions of
the initialization of non-static data members
from <i>brace-or-equal-initializer</i>s (12.6.2).</ins>
<li>&hellip;</ul>
</blockquote>

<p>
Change in 15.4 except.spec paragraph 16:
<p>
<blockquote>
Given a<ins>n implicitly-declared special</ins>
member function <tt>f</tt> of some class <tt>X</tt>,
<del>
where <tt>f</tt> is an inheriting constructor (12.9) or an implicitly-declared special member function,
</del>
the <em>set of potential exceptions of the implicitly-declared <ins>special</ins> member function</em>
<tt>f</tt> consists of all the members from the following sets: &hellip;
</blockquote>

<p>
Change in 15.4 except.spec paragraph 17:
<p>
<blockquote>
An <del>inheriting constructor (12.9) and an</del>
implicitly-declared special member function (Clause 12)
<del>are</del><ins>is</ins> considered to have an implicit exception specification,
as follows,
where S is the set of potential exceptions of the implicitly-declared <ins>special</ins> member function.
<ul><li>&hellip;</ul>
<del>
[ Note: An instantiation of an inheriting constructor template has an implied exception specification as if it
were a non-template inheriting constructor. &mdash; end note ]
</del>
[ Example: &hellip; ]
</blockquote>

</body></html>
