Topic: A Value for Default Initializing objects


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 12 Dec 2016 13:22:14 -0800 (PST)
Raw View
------=_Part_2309_58586277.1481577734671
Content-Type: multipart/alternative;
 boundary="----=_Part_2310_150508201.1481577734671"

------=_Part_2310_150508201.1481577734671
Content-Type: text/plain; charset=UTF-8

Through `emplace`-style APIs, we can initialize values from a sequence of
values. One thing we lack is the ability to initialize via default
initialization. Even `emplace()` will perform value initialization.

Of course, this is not a new C++ problem. While default initialization is
the... default, it's only the default when not using constructor syntax or
list initialization. When using either syntax, it is impossible to perform
default initialization. So... let us change that.

The standard library can declare a type, `std::default_init_t`, as well as
a value `std::default_init` which is of that type. `default_init_t` is a
magic type whose values invoke default initialization of any type. So if
you return `default_init`, you will return a default initialized value of
the function's return type.

So all of the following perform default initialization, regardless of `T`:

T t = std::default_init;
T t(std::default_init);
T t = {std::default_init};
T t{std::default_init};

Since `default_init` is a value of a known type, you can pass it around to
`emplace`-style functions. Therefore,
`vector<int>::emplace_back(default_init)` will perform default
initialization. Or more exactly, `emplace_back` will call
`allocator_traits::construct`, which will call `int(default_init)`, which
will perform default initialization. And a good compiler should be able to
eliminate the whole chain of initialization.

Note that `std::default_init_t` is not implicitly convertible to any `T`.
That's why I think it needs to be something the language reacts to
directly. If it were just using existing implicit conversion rules, you
could get all kinds of problems. Consider this:

class Foo
{
public:
  Foo(int x);
};

Foo foo(std::default_init);

Does this call `Foo::Foo` with a default-initialized `int`, or a
default-initialized `Foo` object? The compiler can't tell the difference.
So to make this work, some form of magic has to be going on.

With explicit language support, this would provoke default initialization
of `Foo`; if you want to call it with a default initialized object, you
have to qualify it: `Foo foo(int(std::default_init));`

As with `in_place`, `default_init` should be the only value of this type,
with all others being copied/moved from this.

One of the advantages of using a type is that, like with `nullptr_t`, we
can create function overloads that detect it. For example:

vector<T> v(200, std::default_init);

Rather than default initializing one value and then copying it to 200
others, we can create an overload specifically for `default_init_t` that
default initializes 200 values. If `T` is trivially default constructible,
then `allocator_traits::construct(default_init_t)` will perform trivial
default initialization. And if
`allocator_traits::construct(default_init_t)` doesn't do anything except
call placement new, the compiler can hopefully boil the entire
initialization loop down to a no-op.

The same would go for all other insertion-type operations.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/0be6b704-0bda-4706-85f9-e548bb3a3ef0%40isocpp.org.

------=_Part_2310_150508201.1481577734671
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Through `emplace`-style APIs, we can initialize values fro=
m a sequence of values. One thing we lack is the ability to initialize via =
default initialization. Even `emplace()` will perform value initialization.=
<br><br>Of course, this is not a new C++ problem. While default initializat=
ion is the... default, it&#39;s only the default when not using constructor=
 syntax or list initialization. When using either syntax, it is impossible =
to perform default initialization. So... let us change that.<br><br>The sta=
ndard library can declare a type, `std::default_init_t`, as well as a value=
 `std::default_init` which is of that type. `default_init_t` is a magic typ=
e whose values invoke default initialization of any type. So if you return =
`default_init`, you will return a default initialized value of the function=
&#39;s return type.<br><br>So all of the following perform default initiali=
zation, regardless of `T`:<br><br><div style=3D"background-color: rgb(250, =
250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-wi=
dth: 1px; overflow-wrap: break-word;" class=3D"prettyprint"><code class=3D"=
prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">T t </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">d=
efault_init</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>T t<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">default_init</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br>T t </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify">std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">default_=
init</span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>T t</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">default_init</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">};</span></div></code></div><br>Since `=
default_init` is a value of a known type, you can pass it around to `emplac=
e`-style functions. Therefore, `vector&lt;int&gt;::emplace_back(default_ini=
t)` will perform default initialization. Or more exactly, `emplace_back` wi=
ll call `allocator_traits::construct`, which will call `int(default_init)`,=
 which will perform default initialization. And a good compiler should be a=
ble to eliminate the whole chain of initialization.<br><br>Note that `std::=
default_init_t` is not implicitly convertible to any `T`. That&#39;s why I =
think it needs to be something the language reacts to directly. If it were =
just using existing implicit conversion rules, you could get all kinds of p=
roblems. Consider this:<br><br><div style=3D"background-color: rgb(250, 250=
, 250); border-color: rgb(187, 187, 187); border-style: solid; border-width=
: 1px; overflow-wrap: break-word;" class=3D"prettyprint"><code class=3D"pre=
ttyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=
=3D"styled-by-prettify">class</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-=
prettify">Foo</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">public</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">Foo</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;=
" class=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> x</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><b=
r></span><span style=3D"color: #606;" class=3D"styled-by-prettify">Foo</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> foo</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">default_init</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">);</span></div></code></div><br>Does this=
 call `Foo::Foo` with a default-initialized `int`, or a default-initialized=
 `Foo` object? The compiler can&#39;t tell the difference. So to make this =
work, some form of magic has to be going on.<br><br>With explicit language =
support, this would provoke default initialization of `Foo`; if you want to=
 call it with a default initialized object, you have to qualify it: `Foo fo=
o(int(std::default_init));`<br><br>As with `in_place`, `default_init` shoul=
d be the only value of this type, with all others being copied/moved from t=
his.<br><br>One of the advantages of using a type is that, like with `nullp=
tr_t`, we can create function overloads that detect it. For example:<br><br=
><div style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187,=
 187, 187); border-style: solid; border-width: 1px; overflow-wrap: break-wo=
rd;" class=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subpre=
ttyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">vector<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">T</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> v</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #066;" cla=
ss=3D"styled-by-prettify">200</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">defa=
ult_init</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span=
></div></code></div><br>Rather than default initializing one value and then=
 copying it to 200 others, we can create an overload specifically for `defa=
ult_init_t` that default initializes 200 values. If `T` is trivially defaul=
t constructible, then `allocator_traits::construct(default_init_t)` will pe=
rform trivial default initialization. And if `allocator_traits::construct(d=
efault_init_t)` doesn&#39;t do anything except call placement new, the comp=
iler can hopefully boil the entire initialization loop down to a no-op.<br>=
<br>The same would go for all other insertion-type operations.<br></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/0be6b704-0bda-4706-85f9-e548bb3a3ef0%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/0be6b704-0bda-4706-85f9-e548bb3a3ef0=
%40isocpp.org</a>.<br />

------=_Part_2310_150508201.1481577734671--

------=_Part_2309_58586277.1481577734671--

.


Author: Barry Revzin <barry.revzin@gmail.com>
Date: Tue, 13 Dec 2016 10:11:47 -0800 (PST)
Raw View
------=_Part_942_558231253.1481652707309
Content-Type: multipart/alternative;
 boundary="----=_Part_943_1866548600.1481652707309"

------=_Part_943_1866548600.1481652707309
Content-Type: text/plain; charset=UTF-8


>
> One of the advantages of using a type is that, like with `nullptr_t`, we
> can create function overloads that detect it. For example:
>
> vector<T> v(200, std::default_init);
>
>
This is definitely a lot nicer than the current approaches to
default-initializing elements (either writing your own allocator which does
default initialization or having to write vector<wrapper<T>>).

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e3a1f20d-b907-4808-8510-211e590435ab%40isocpp.org.

------=_Part_943_1866548600.1481652707309
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr">One of the advantages of using a type is that, like with `nullptr_t`, w=
e can create function overloads that detect it. For example:<br><br><div st=
yle=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bord=
er-style:solid;border-width:1px"><code><div><span style=3D"color:#000">vect=
or</span><span style=3D"color:#660">&lt;</span><span style=3D"color:#000">T=
</span><span style=3D"color:#660">&gt;</span><span style=3D"color:#000"> v<=
/span><span style=3D"color:#660">(</span><span style=3D"color:#066">200</sp=
an><span style=3D"color:#660">,</span><span style=3D"color:#000"> std</span=
><span style=3D"color:#660">::</span><span style=3D"color:#000">default_ini=
t</span><span style=3D"color:#660">);</span><span style=3D"color:#000"><br>=
</span></div></code></div><br></div></blockquote><div><br></div><div>This i=
s definitely a lot nicer than the current approaches to default-initializin=
g elements (either writing your own allocator which does default initializa=
tion or having to write <font face=3D"courier new, monospace">vector&lt;wra=
pper&lt;T&gt;&gt;</font>).=C2=A0</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/e3a1f20d-b907-4808-8510-211e590435ab%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/e3a1f20d-b907-4808-8510-211e590435ab=
%40isocpp.org</a>.<br />

------=_Part_943_1866548600.1481652707309--

------=_Part_942_558231253.1481652707309--

.


Author: Sean Middleditch <sean.middleditch@gmail.com>
Date: Fri, 16 Dec 2016 23:41:41 -0800 (PST)
Raw View
------=_Part_2587_1258588604.1481960501553
Content-Type: multipart/alternative;
 boundary="----=_Part_2588_581818350.1481960501553"

------=_Part_2588_581818350.1481960501553
Content-Type: text/plain; charset=UTF-8

I love it.

One concern - you mention that it's a magic type that invokes a default
constructor but also that it can be overloaded in functions. What happens
if a user defines a constructor that takes a default_init_t?

    class foo { foo(std::default_init_t); };

Should it be invoked instead of the (ahem) default behavior? Should it be
ill-formed?

I do something similar in math code where user types have default
constructors that initialize elements to known-safe values (all zeroes,
etc.) but also have constructors parameterized over uninitialized_t with
empty bodies. This works fine except for one weakness: the compiler doesn't
know that the "uninitialized" constructor is trivial because only the
default and copy/move constructors can be trivial.

Which makes me think: perhaps instead of making default_init_t *completely*
magic we could instead loosen the rules for constructor to allow any
constructor to have =default instead of a body. The compiler can then
easily determine if the constructor is trivial or not via the existing
rules. All types could then have a "magic" constructor
foo::foo(std::default_init_t) : foo() = default; implicitly generated if
the default constructor isn't deleted. This also makes the overload
question I posed much simpler to answer since the answer becomes implied. I
think the generality is a better design in (ahem 2) general, but in this
case it also means existing code (like mine) using a similar type/trick can
just replace their empty constructor bodies with =default to become
trivial, just like we did with default constructors in C++11.

On Monday, December 12, 2016 at 1:22:14 PM UTC-8, Nicol Bolas wrote:
>
> Through `emplace`-style APIs, we can initialize values from a sequence of
> values. One thing we lack is the ability to initialize via default
> initialization. Even `emplace()` will perform value initialization.
>
> Of course, this is not a new C++ problem. While default initialization is
> the... default, it's only the default when not using constructor syntax or
> list initialization. When using either syntax, it is impossible to perform
> default initialization. So... let us change that.
>
> The standard library can declare a type, `std::default_init_t`, as well as
> a value `std::default_init` which is of that type. `default_init_t` is a
> magic type whose values invoke default initialization of any type. So if
> you return `default_init`, you will return a default initialized value of
> the function's return type.
>
> So all of the following perform default initialization, regardless of `T`:
>
> T t = std::default_init;
> T t(std::default_init);
> T t = {std::default_init};
> T t{std::default_init};
>
> Since `default_init` is a value of a known type, you can pass it around to
> `emplace`-style functions. Therefore,
> `vector<int>::emplace_back(default_init)` will perform default
> initialization. Or more exactly, `emplace_back` will call
> `allocator_traits::construct`, which will call `int(default_init)`, which
> will perform default initialization. And a good compiler should be able to
> eliminate the whole chain of initialization.
>
> Note that `std::default_init_t` is not implicitly convertible to any `T`.
> That's why I think it needs to be something the language reacts to
> directly. If it were just using existing implicit conversion rules, you
> could get all kinds of problems. Consider this:
>
> class Foo
> {
> public:
>   Foo(int x);
> };
>
> Foo foo(std::default_init);
>
> Does this call `Foo::Foo` with a default-initialized `int`, or a
> default-initialized `Foo` object? The compiler can't tell the difference.
> So to make this work, some form of magic has to be going on.
>
> With explicit language support, this would provoke default initialization
> of `Foo`; if you want to call it with a default initialized object, you
> have to qualify it: `Foo foo(int(std::default_init));`
>
> As with `in_place`, `default_init` should be the only value of this type,
> with all others being copied/moved from this.
>
> One of the advantages of using a type is that, like with `nullptr_t`, we
> can create function overloads that detect it. For example:
>
> vector<T> v(200, std::default_init);
>
> Rather than default initializing one value and then copying it to 200
> others, we can create an overload specifically for `default_init_t` that
> default initializes 200 values. If `T` is trivially default constructible,
> then `allocator_traits::construct(default_init_t)` will perform trivial
> default initialization. And if
> `allocator_traits::construct(default_init_t)` doesn't do anything except
> call placement new, the compiler can hopefully boil the entire
> initialization loop down to a no-op.
>
> The same would go for all other insertion-type operations.
>

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/884e773c-e2d9-45db-9e0a-39029e0b32ab%40isocpp.org.

------=_Part_2588_581818350.1481960501553
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I love it.<div><br></div><div>One concern - you mention th=
at it&#39;s a magic type that invokes a default constructor but also that i=
t can be overloaded in functions. What happens if a user defines a construc=
tor that takes a default_init_t?</div><div><br></div><div>=C2=A0 =C2=A0 cla=
ss foo { foo(std::default_init_t); };</div><div><br></div><div>Should it be=
 invoked instead of the (ahem) default behavior? Should it be ill-formed?</=
div><div><br></div><div>I do something similar in math code where user type=
s have default constructors that initialize elements to known-safe values (=
all zeroes, etc.) but also have constructors parameterized over uninitializ=
ed_t with empty bodies. This works fine except for one weakness: the compil=
er doesn&#39;t know that the &quot;uninitialized&quot; constructor is trivi=
al because only the default and copy/move constructors can be trivial.</div=
><div><br></div><div>Which makes me think: perhaps instead of making defaul=
t_init_t *completely* magic we could instead loosen the rules for construct=
or to allow any constructor to have =3Ddefault instead of a body. The compi=
ler can then easily determine if the constructor is trivial or not via the =
existing rules. All types could then have a &quot;magic&quot; constructor f=
oo::foo(std::default_init_t) : foo() =3D default; implicitly generated if t=
he default constructor isn&#39;t deleted. This also makes the overload ques=
tion I posed much simpler to answer since the answer becomes implied. I thi=
nk the generality is a better design in (ahem 2) general, but in this case =
it also means existing code (like mine) using a similar type/trick can just=
 replace their empty constructor bodies with =3Ddefault to become trivial, =
just like we did with default constructors in C++11.<br><div><br>On Monday,=
 December 12, 2016 at 1:22:14 PM UTC-8, Nicol Bolas wrote:<blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div dir=3D"ltr">Through `emplace`-style APIs, =
we can initialize values from a sequence of values. One thing we lack is th=
e ability to initialize via default initialization. Even `emplace()` will p=
erform value initialization.<br><br>Of course, this is not a new C++ proble=
m. While default initialization is the... default, it&#39;s only the defaul=
t when not using constructor syntax or list initialization. When using eith=
er syntax, it is impossible to perform default initialization. So... let us=
 change that.<br><br>The standard library can declare a type, `std::default=
_init_t`, as well as a value `std::default_init` which is of that type. `de=
fault_init_t` is a magic type whose values invoke default initialization of=
 any type. So if you return `default_init`, you will return a default initi=
alized value of the function&#39;s return type.<br><br>So all of the follow=
ing perform default initialization, regardless of `T`:<br><br><div style=3D=
"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-sty=
le:solid;border-width:1px"><code><div><span style=3D"color:#000">T t </span=
><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> std</span=
><span style=3D"color:#660">::</span><span style=3D"color:#000">default_ini=
t</span><span style=3D"color:#660">;</span><span style=3D"color:#000"><br>T=
 t</span><span style=3D"color:#660">(</span><span style=3D"color:#000">std<=
/span><span style=3D"color:#660">::</span><span style=3D"color:#000">defaul=
t_init</span><span style=3D"color:#660">);</span><span style=3D"color:#000"=
><br>T t </span><span style=3D"color:#660">=3D</span><span style=3D"color:#=
000"> </span><span style=3D"color:#660">{</span><span style=3D"color:#000">=
std</span><span style=3D"color:#660">::</span><span style=3D"color:#000">de=
fault_init</span><span style=3D"color:#660">};</span><span style=3D"color:#=
000"><br>T t</span><span style=3D"color:#660">{</span><span style=3D"color:=
#000">std</span><span style=3D"color:#660">::</span><span style=3D"color:#0=
00">default_init</span><span style=3D"color:#660">};</span></div></code></d=
iv><br>Since `default_init` is a value of a known type, you can pass it aro=
und to `emplace`-style functions. Therefore, `vector&lt;int&gt;::emplace_ba=
ck(<wbr>default_init)` will perform default initialization. Or more exactly=
, `emplace_back` will call `allocator_traits::construct`, which will call `=
int(default_init)`, which will perform default initialization. And a good c=
ompiler should be able to eliminate the whole chain of initialization.<br><=
br>Note that `std::default_init_t` is not implicitly convertible to any `T`=
.. That&#39;s why I think it needs to be something the language reacts to di=
rectly. If it were just using existing implicit conversion rules, you could=
 get all kinds of problems. Consider this:<br><br><div style=3D"background-=
color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;bor=
der-width:1px"><code><div><span style=3D"color:#008">class</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#606">Foo</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#660">{</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#008">public</span><span st=
yle=3D"color:#660">:</span><span style=3D"color:#000"><br>=C2=A0 </span><sp=
an style=3D"color:#606">Foo</span><span style=3D"color:#660">(</span><span =
style=3D"color:#008">int</span><span style=3D"color:#000"> x</span><span st=
yle=3D"color:#660">);</span><span style=3D"color:#000"><br></span><span sty=
le=3D"color:#660">};</span><span style=3D"color:#000"><br><br></span><span =
style=3D"color:#606">Foo</span><span style=3D"color:#000"> foo</span><span =
style=3D"color:#660">(</span><span style=3D"color:#000">std</span><span sty=
le=3D"color:#660">::</span><span style=3D"color:#000">default_init</span><s=
pan style=3D"color:#660">);</span></div></code></div><br>Does this call `Fo=
o::Foo` with a default-initialized `int`, or a default-initialized `Foo` ob=
ject? The compiler can&#39;t tell the difference. So to make this work, som=
e form of magic has to be going on.<br><br>With explicit language support, =
this would provoke default initialization of `Foo`; if you want to call it =
with a default initialized object, you have to qualify it: `Foo foo(int(std=
::default_init));`<br><br>As with `in_place`, `default_init` should be the =
only value of this type, with all others being copied/moved from this.<br><=
br>One of the advantages of using a type is that, like with `nullptr_t`, we=
 can create function overloads that detect it. For example:<br><br><div sty=
le=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);borde=
r-style:solid;border-width:1px"><code><div><span style=3D"color:#000">vecto=
r</span><span style=3D"color:#660">&lt;</span><span style=3D"color:#000">T<=
/span><span style=3D"color:#660">&gt;</span><span style=3D"color:#000"> v</=
span><span style=3D"color:#660">(</span><span style=3D"color:#066">200</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> std</span>=
<span style=3D"color:#660">::</span><span style=3D"color:#000">default_init=
</span><span style=3D"color:#660">);</span><span style=3D"color:#000"><br><=
/span></div></code></div><br>Rather than default initializing one value and=
 then copying it to 200 others, we can create an overload specifically for =
`default_init_t` that default initializes 200 values. If `T` is trivially d=
efault constructible, then `allocator_traits::construct(<wbr>default_init_t=
)` will perform trivial default initialization. And if `allocator_traits::c=
onstruct(<wbr>default_init_t)` doesn&#39;t do anything except call placemen=
t new, the compiler can hopefully boil the entire initialization loop down =
to a no-op.<br><br>The same would go for all other insertion-type operation=
s.<br></div></blockquote></div></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/884e773c-e2d9-45db-9e0a-39029e0b32ab%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/884e773c-e2d9-45db-9e0a-39029e0b32ab=
%40isocpp.org</a>.<br />

------=_Part_2588_581818350.1481960501553--

------=_Part_2587_1258588604.1481960501553--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 17 Dec 2016 08:26:26 -0800 (PST)
Raw View
------=_Part_2744_1583510743.1481991986622
Content-Type: multipart/alternative;
 boundary="----=_Part_2745_170136307.1481991986622"

------=_Part_2745_170136307.1481991986622
Content-Type: text/plain; charset=UTF-8

On Saturday, December 17, 2016 at 2:41:41 AM UTC-5, Sean Middleditch wrote:
>
> I love it.
>
> One concern - you mention that it's a magic type that invokes a default
> constructor but also that it can be overloaded in functions. What happens
> if a user defines a constructor that takes a default_init_t?
>
>     class foo { foo(std::default_init_t); };
>
> Should it be invoked instead of the (ahem) default behavior? Should it be
> ill-formed?
>

No, it should not be ill-formed. It just won't be *called*. Default
initialization via a single value of `default_init_t` type should have
priority over all other initialization forms.

The reason for not making it flat-out illegal is that you might have a
constructor that takes a `default_init_t` first parameter, but also has
optional parameters beyond that. You won't be able to invoke that
constructor without supplying one of those optional parameters.

I do something similar in math code where user types have default
> constructors that initialize elements to known-safe values (all zeroes,
> etc.) but also have constructors parameterized over uninitialized_t with
> empty bodies. This works fine except for one weakness: the compiler doesn't
> know that the "uninitialized" constructor is trivial because only the
> default and copy/move constructors can be trivial.
>
> Which makes me think: perhaps instead of making default_init_t
> *completely* magic we could instead loosen the rules for constructor to
> allow any constructor to have =default instead of a body. The compiler can
> then easily determine if the constructor is trivial or not via the existing
> rules. All types could then have a "magic" constructor
> foo::foo(std::default_init_t) : foo() = default; implicitly generated if
> the default constructor isn't deleted. This also makes the overload
> question I posed much simpler to answer since the answer becomes implied. I
> think the generality is a better design in (ahem 2) general, but in this
> case it also means existing code (like mine) using a similar type/trick can
> just replace their empty constructor bodies with =default to become
> trivial, just like we did with default constructors in C++11.
>

I *really* don't like this idea.

The whole point of this feature is to permit a user to default initialize
any type `T` by doing `T t = default_init;`. Therefore, that statement must
always be *equivalent* to `T t;`.

If you use this magic constructor method, users can now *override*
`default_init_t` initialization. That completely destroys the whole purpose
of the feature. `T t`; will always follow [dcl.init]/7, while `T t =
default_init;` is just like any other constructor call.

I get what you're wanting. You want `T t` to call a default constructor,
while making `T t(something)` perform the equivalent of actual "default
initialization".

I would say that the way to handle this is to permit a user to define a
constructor which performs default initialization of the object's members.
Like this:

struct A
{
  A() /*non-trivial default construction*/
  A(uninitialize_t) = default_init;
};

The code generated for that constructor will default initialize its
subobjects, overriding all default member initializers and such. If one of
the subobjects is not trivially default constructible, then this function
will not be a trivial constructor. If one of the subobjects cannot undergo
default initialization (deleted default constructor, a reference, etc),
this definition will be il-formed.

I think this would work better for your needs. We keep `A a;` equivalent to
`A a = default_init;`: they both call the default constructor, which in
this case is non-trivial. But `A a = uninitialize_t{};` will default
initialize the members, effectively doing nothing. It can be a trivial
constructor, testable via `is_trivially_constructible<A, uninitialize_t>`.
It will be a noexcept constructor, so long as any constructors it calls are
noexcept. And so forth.

In effect, the above declaration is like this:

A(uninitialize_t) base_classes(default_init)..., members(default_init)... {}

Except that the compiler is aware that this is what's going on and it can
therefore optimize it away.

To do this, I believe this means that `default_init` will now have to be a
keyword, much like `nullptr` and its relationship to `std::nullptr_t`.
Unless we can put special identifiers in the `= stuff` part of a function
declaration.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ef39ea40-0732-449c-8aef-c0e85ab1457b%40isocpp.org.

------=_Part_2745_170136307.1481991986622
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Saturday, December 17, 2016 at 2:41:41 AM UTC-5, Sean M=
iddleditch wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr">I love it.<div><br></div><div>One concern - you mention that it&#39;s a=
 magic type that invokes a default constructor but also that it can be over=
loaded in functions. What happens if a user defines a constructor that take=
s a default_init_t?</div><div><br></div><div>=C2=A0 =C2=A0 class foo { foo(=
std::default_init_t); };</div><div><br></div><div>Should it be invoked inst=
ead of the (ahem) default behavior? Should it be ill-formed?</div></div></b=
lockquote><div><br>No, it should not be ill-formed. It just won&#39;t be <i=
>called</i>. Default initialization via a single value of `default_init_t` =
type should have priority over all other initialization forms.<br><br>The r=
eason for not making it flat-out illegal is that you might have a construct=
or that takes a `default_init_t` first parameter, but also has optional par=
ameters beyond that. You won&#39;t be able to invoke that constructor witho=
ut supplying one of those optional parameters.<br><br></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #=
ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></div><div>I do somethi=
ng similar in math code where user types have default constructors that ini=
tialize elements to known-safe values (all zeroes, etc.) but also have cons=
tructors parameterized over uninitialized_t with empty bodies. This works f=
ine except for one weakness: the compiler doesn&#39;t know that the &quot;u=
ninitialized&quot; constructor is trivial because only the default and copy=
/move constructors can be trivial.</div><div><br></div><div>Which makes me =
think: perhaps instead of making default_init_t *completely* magic we could=
 instead loosen the rules for constructor to allow any constructor to have =
=3Ddefault instead of a body. The compiler can then easily determine if the=
 constructor is trivial or not via the existing rules. All types could then=
 have a &quot;magic&quot; constructor foo::foo(std::default_init_t) : foo()=
 =3D default; implicitly generated if the default constructor isn&#39;t del=
eted. This also makes the overload question I posed much simpler to answer =
since the answer becomes implied. I think the generality is a better design=
 in (ahem 2) general, but in this case it also means existing code (like mi=
ne) using a similar type/trick can just replace their empty constructor bod=
ies with =3Ddefault to become trivial, just like we did with default constr=
uctors in C++11.<br></div></div></blockquote><div><br>I <i>really</i> don&#=
39;t like this idea.<br><br>The whole point of this feature is to permit a =
user to default initialize any type `T` by doing `T t =3D default_init;`. T=
herefore, that statement must always be <i>equivalent</i> to `T t;`.<br><br=
>If you use this magic constructor method, users can now <i>override</i> `d=
efault_init_t` initialization. That completely destroys the whole purpose o=
f the feature. `T t`; will always follow [dcl.init]/7, while `T t =3D defau=
lt_init;` is just like any other constructor call.<br><br>I get what you&#3=
9;re wanting. You want `T t` to call a default constructor, while making `T=
 t(something)` perform the equivalent of actual &quot;default initializatio=
n&quot;.<br><br>I would say that the way to handle this is to permit a user=
 to define a constructor which performs default initialization of the objec=
t&#39;s members. Like this:<br><br><div style=3D"background-color: rgb(250,=
 250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-w=
idth: 1px; overflow-wrap: break-word;" class=3D"prettyprint"><code class=3D=
"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">struct</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> A<br></span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br>=C2=A0 A</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">()</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">/*no=
n-trivial default construction*/</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 A</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">uninitialize_t</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> def=
ault_init</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span></div><=
/code></div><br>The code generated for that constructor will default initia=
lize its subobjects, overriding all default member initializers and such. I=
f one of the subobjects is not trivially default constructible, then this f=
unction will not be a trivial constructor. If one of the subobjects cannot =
undergo default initialization (deleted default constructor, a reference, e=
tc), this definition will be il-formed.<br><br>I think this would work bett=
er for your needs. We keep `A a;` equivalent to `A a =3D default_init;`: th=
ey both call the default constructor, which in this case is non-trivial. Bu=
t `A a =3D uninitialize_t{};` will default initialize the members, effectiv=
ely doing nothing. It can be a trivial constructor, testable via `is_trivia=
lly_constructible&lt;A, uninitialize_t&gt;`. It will be a noexcept construc=
tor, so long as any constructors it calls are noexcept. And so forth.<br><b=
r>In effect, the above declaration is like this:<br><br><div style=3D"backg=
round-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-s=
tyle: solid; border-width: 1px; overflow-wrap: break-word;" class=3D"pretty=
print"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">A</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify">uninitialize_t</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> base_classes</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">default_init</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">)...,</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> members</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">default_init</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">)...</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{}</span=
></div></code></div><br>Except that the compiler is aware that this is what=
&#39;s going on and it can therefore optimize it away.<br><br>To do this, I=
 believe this means that `default_init` will now have to be a keyword, much=
 like `nullptr` and its relationship to `std::nullptr_t`. Unless we can put=
 special identifiers in the `=3D stuff` part of a function declaration.</di=
v></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/ef39ea40-0732-449c-8aef-c0e85ab1457b%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/ef39ea40-0732-449c-8aef-c0e85ab1457b=
%40isocpp.org</a>.<br />

------=_Part_2745_170136307.1481991986622--

------=_Part_2744_1583510743.1481991986622--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 17 Dec 2016 15:00:05 -0800 (PST)
Raw View
------=_Part_978_428741365.1482015605824
Content-Type: multipart/alternative;
 boundary="----=_Part_979_439944954.1482015605824"

------=_Part_979_439944954.1482015605824
Content-Type: text/plain; charset=UTF-8



On Saturday, December 17, 2016 at 11:26:26 AM UTC-5, Nicol Bolas wrote:
>
> On Saturday, December 17, 2016 at 2:41:41 AM UTC-5, Sean Middleditch wrote:
>>
>> I love it.
>>
>> One concern - you mention that it's a magic type that invokes a default
>> constructor but also that it can be overloaded in functions. What happens
>> if a user defines a constructor that takes a default_init_t?
>>
>>     class foo { foo(std::default_init_t); };
>>
>> Should it be invoked instead of the (ahem) default behavior? Should it be
>> ill-formed?
>>
>
> No, it should not be ill-formed. It just won't be *called*. Default
> initialization via a single value of `default_init_t` type should have
> priority over all other initialization forms.
>

I realized something. It is possible to call such a constructor. It
requires implicit conversions. If you have some type U, you can make it
implicitly convertible to `default_init_t`. And the check for the type
being used to initialize the value happens first, before attempting
implicit conversions. So it is possible to call this constructor.

I'm not sure how useful this is. Even so, I'm still against forbidding this
constructor declaration. Indeed, we might even normalize it by providing
some standard library type that is implicitly convertible to
`default_init_t`.

I also am thinking of walking back the idea of having `T t =
{default_init}` being equivalent to `T t = default_init`. The idea being
that if `T` is an aggregate, you probably want `{default_init}` to mean
"default initialize the first element and value-initialize the rest, if
any".

So while `T t(default_init)` must mean "default initialize `T`, no matter
what `T` is", `T t{default_init}` needs to be something different.

If `T` is not an aggregate, then applying `{default_init} should invoke
constructors as normal. `default_init_t` can default initialize a value of
any type. It is essentially a conversion step, so overload resolution ought
to still work for it. Obviously, it can lead to ambiguity, but if there is
a matching `default_init_t` in the constructor sequence, it ought to work.

So, direct initialization from a single `default_init_t` value means to
default initialize the `T`; this is what allows us to invoke this through
`emplace` and the like. Copy initialization from a single `default_init_t`
value means to default initialize. List initialization with a single
`default_init_t` on a type T means to pass that to the first element of the
aggregate/constructor.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/72b3f133-b277-43e4-93c1-ab29b2cf6483%40isocpp.org.

------=_Part_979_439944954.1482015605824
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Saturday, December 17, 2016 at 11:26:26 AM UTC-=
5, Nicol Bolas wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;m=
argin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr">On Saturday, December 17, 2016 at 2:41:41 AM UTC-5, Sean Middledit=
ch wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">I love it=
..<div><br></div><div>One concern - you mention that it&#39;s a magic type t=
hat invokes a default constructor but also that it can be overloaded in fun=
ctions. What happens if a user defines a constructor that takes a default_i=
nit_t?</div><div><br></div><div>=C2=A0 =C2=A0 class foo { foo(std::default_=
init_t); };</div><div><br></div><div>Should it be invoked instead of the (a=
hem) default behavior? Should it be ill-formed?</div></div></blockquote><di=
v><br>No, it should not be ill-formed. It just won&#39;t be <i>called</i>. =
Default initialization via a single value of `default_init_t` type should h=
ave priority over all other initialization forms.<br></div></div></blockquo=
te><div><br>I realized something. It is possible to call such a constructor=
.. It requires implicit conversions. If you have some type U, you can make i=
t implicitly convertible to `default_init_t`. And the check for the type be=
ing used to initialize the value happens first, before attempting implicit =
conversions. So it is possible to call this constructor.<br><br>I&#39;m not=
 sure how useful this is. Even so, I&#39;m still against forbidding this co=
nstructor declaration. Indeed, we might even normalize it by providing some=
 standard library type that is implicitly convertible to `default_init_t`.<=
br><br>I also am thinking of walking back the idea of having `T t =3D {defa=
ult_init}` being equivalent to `T t =3D default_init`. The idea being that =
if `T` is an aggregate, you probably want `{default_init}` to mean &quot;de=
fault initialize the first element and value-initialize the rest, if any&qu=
ot;.<br><br>So while `T t(default_init)` must mean &quot;default initialize=
 `T`, no matter what `T` is&quot;, `T t{default_init}` needs to be somethin=
g different.<br><br>If `T` is not an aggregate, then applying `{default_ini=
t} should invoke constructors as normal. `default_init_t` can default initi=
alize a value of any type. It is essentially a conversion step, so overload=
 resolution ought to still work for it. Obviously, it can lead to ambiguity=
, but if there is a matching `default_init_t` in the constructor sequence, =
it ought to work.<br><br>So, direct initialization from a single `default_i=
nit_t` value means to default initialize the `T`; this is what allows us to=
 invoke this through `emplace` and the like. Copy initialization from a sin=
gle `default_init_t` value means to default initialize. List initialization=
 with a single `default_init_t` on a type T means to pass that to the first=
 element of the aggregate/constructor.<br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/72b3f133-b277-43e4-93c1-ab29b2cf6483%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/72b3f133-b277-43e4-93c1-ab29b2cf6483=
%40isocpp.org</a>.<br />

------=_Part_979_439944954.1482015605824--

------=_Part_978_428741365.1482015605824--

.


Author: Sean Middleditch <sean.middleditch@gmail.com>
Date: Sun, 18 Dec 2016 22:43:28 -0800 (PST)
Raw View
------=_Part_159_2083619575.1482129808883
Content-Type: multipart/alternative;
 boundary="----=_Part_160_1278212634.1482129808884"

------=_Part_160_1278212634.1482129808884
Content-Type: text/plain; charset=UTF-8

On Saturday, December 17, 2016 at 8:26:26 AM UTC-8, Nicol Bolas wrote:
>
> Which makes me think: perhaps instead of making default_init_t
>> *completely* magic we could instead loosen the rules for constructor to
>> allow any constructor to have =default instead of a body. The compiler can
>> then easily determine if the constructor is trivial or not via the existing
>> rules. All types could then have a "magic" constructor
>> foo::foo(std::default_init_t) : foo() = default; implicitly generated if
>> the default constructor isn't deleted. This also makes the overload
>> question I posed much simpler to answer since the answer becomes implied. I
>> think the generality is a better design in (ahem 2) general, but in this
>> case it also means existing code (like mine) using a similar type/trick can
>> just replace their empty constructor bodies with =default to become
>> trivial, just like we did with default constructors in C++11.
>>
>
> I *really* don't like this idea.
>
> The whole point of this feature is to permit a user to default initialize
> any type `T` by doing `T t = default_init;`. Therefore, that statement must
> always be *equivalent* to `T t;`.
>

Here we'll disagree then. :)

The magic value approach sits very poorly with me. I'd prefer to minimize
its impact on the language to the smallest possible degree. I believe your
use case can be achieve with nothing more than introducing the
automatically generated constructor _if_ there's also a way to note that
forwarded constructors can inherit triviality... which my added suggestions
provides (and that suggestion provides more use cases than just making your
feature work, which implies that it has relatively high value so far as the
difficulty-to-usefulness ratio goes).


> If you use this magic constructor method, users can now *override*
> `default_init_t` initialization. That completely destroys the whole purpose
> of the feature. `T t`; will always follow [dcl.init]/7, while `T t =
> default_init;` is just like any other constructor call.
>

Unless of course that's what the author of the library wanted. Why
shouldn't an expert library author be able to override the constructor?
There are valid use cases to be able to override just about everything
else, which is allowed. I don't think it's terribly important to be able to
override it, but I'm not sure what you're really buying in real-world
utility by adding special cases here.


> I get what you're wanting. You want `T t` to call a default constructor,
> while making `T t(something)` perform the equivalent of actual "default
> initialization".
>
> I would say that the way to handle this is to permit a user to define a
> constructor which performs default initialization of the object's members.
> Like this:
>
> struct A
> {
>   A() /*non-trivial default construction*/
>   A(uninitialize_t) = default_init;
> };
>
> The code generated for that constructor will default initialize its
> subobjects, overriding all default member initializers and such. If one of
> the subobjects is not trivially default constructible, then this function
> will not be a trivial constructor. If one of the subobjects cannot undergo
> default initialization (deleted default constructor, a reference, etc),
> this definition will be il-formed.
>

Yeah, that too, though I see no reason why it needs to be a new
=default_init instead of just =default.

Remember that A::A() = default; is perfectly legal. Extending that to
A::A(foo) = default or A::A(foo) : A() = default is a small step. The
=default basically translates to "ignore implicit supression if present and
supply a trivial empty body; if all other invoked member initializations,
implicit or explicit, are trivial, then this is trivial as well."

    class A {
      int x;
    public:
      A() = default; // trivial
      A(int x) : x(x) = default; // not trivial
      A(ignore_t) = default; // trivial
      A(default_init) : A() = default; // trivial
      A(int* p) : A(*p) = default; // not trivial
    };


> I think this would work better for your needs. We keep `A a;` equivalent
> to `A a = default_init;`: they both call the default constructor, which in
> this case is non-trivial. But `A a = uninitialize_t{};` will default
> initialize the members, effectively doing nothing. It can be a trivial
> constructor, testable via `is_trivially_constructible<A, uninitialize_t>`.
> It will be a noexcept constructor, so long as any constructors it calls are
> noexcept. And so forth.
>

I agree that all works, and given your proposal being formalized and
accepted, is totally good. :)


>
> In effect, the above declaration is like this:
>
> A(uninitialize_t) base_classes(default_init)..., members(default_init)...
> {}
>
> Except that the compiler is aware that this is what's going on and it can
> therefore optimize it away.
>
> To do this, I believe this means that `default_init` will now have to be a
> keyword, much like `nullptr` and its relationship to `std::nullptr_t`.
> Unless we can put special identifiers in the `= stuff` part of a function
> declaration.
>

I don't think so at all. Trivialness doesn't require any new keywords or
semantics; the only thing blocking it from being applicable to any function
is the presence of the empty body and the fact that =default can currently
only be applied to compiler generator functions.

Automatic generation of type(std::default_init_t) is one step necessary for
your proposed syntax no matter what. Allowing =default on any function body
solves my use case _and_ completes your feature with no additional one-off
semantics; two "small" features combine to satisfy both of our use cases. :)

   class mytype {
   public:
     mytype() = default;
     // automatically generated:
     mytype(std::default_init_t) : mytype() = default;
   };

   class safesimd {
     float x, y;
   public:
     safesimd() : x(0), y(0) {} // non-trivial, safe defaults
     safesimd(unitialized_t) = default; // trivial, members default
initialized

     // automatically generated:
     safesimd(std::default_init_t) : safesimd() = default;
   };

In short, I think we can get both what we want independent of the
disagreement, e.g. whether the default_init constructor is overridable is
immaterial to the tweaks I'm suggesting. For reference though, the
disagreement basically boils down to:

   class disagreement {
   public:
     disagreement() = default;

     // user-supplied override:
     disagreement(std::default_init_t) { /* fancy meta-programming or
something */ }

     // or maybe even deleted
     disagreement(std::default_init_t) = delete;
   };

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b851c076-a90b-446d-be90-bb832132f840%40isocpp.org.

------=_Part_160_1278212634.1482129808884
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Saturday, December 17, 2016 at 8:26:26 AM UTC-8, Nicol =
Bolas wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><=
blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border=
-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>Which makes me=
 think: perhaps instead of making default_init_t *completely* magic we coul=
d instead loosen the rules for constructor to allow any constructor to have=
 =3Ddefault instead of a body. The compiler can then easily determine if th=
e constructor is trivial or not via the existing rules. All types could the=
n have a &quot;magic&quot; constructor foo::foo(std::default_init_t) : foo(=
) =3D default; implicitly generated if the default constructor isn&#39;t de=
leted. This also makes the overload question I posed much simpler to answer=
 since the answer becomes implied. I think the generality is a better desig=
n in (ahem 2) general, but in this case it also means existing code (like m=
ine) using a similar type/trick can just replace their empty constructor bo=
dies with =3Ddefault to become trivial, just like we did with default const=
ructors in C++11.<br></div></div></blockquote><div><br>I <i>really</i> don&=
#39;t like this idea.<br><br>The whole point of this feature is to permit a=
 user to default initialize any type `T` by doing `T t =3D default_init;`. =
Therefore, that statement must always be <i>equivalent</i> to `T t;`.<br></=
div></div></blockquote><div><br></div><div>Here we&#39;ll disagree then. :)=
</div><div><br></div><div>The magic value approach sits very poorly with me=
.. I&#39;d prefer to minimize its impact on the language to the smallest pos=
sible degree. I believe your use case can be achieve with nothing more than=
 introducing the automatically generated constructor _if_ there&#39;s also =
a way to note that forwarded constructors can inherit triviality... which m=
y added suggestions provides (and that suggestion provides more use cases t=
han just making your feature work, which implies that it has relatively hig=
h value so far as the difficulty-to-usefulness ratio goes).</div><div>=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div=
>If you use this magic constructor method, users can now <i>override</i> `d=
efault_init_t` initialization. That completely destroys the whole purpose o=
f the feature. `T t`; will always follow [dcl.init]/7, while `T t =3D defau=
lt_init;` is just like any other constructor call.<br></div></div></blockqu=
ote><div><br></div><div>Unless of course that&#39;s what the author of the =
library wanted. Why shouldn&#39;t an expert library author be able to overr=
ide the constructor? There are valid use cases to be able to override just =
about everything else, which is allowed. I don&#39;t think it&#39;s terribl=
y important to be able to override it, but I&#39;m not sure what you&#39;re=
 really buying in real-world utility by adding special cases here.</div><di=
v>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"=
><div>I get what you&#39;re wanting. You want `T t` to call a default const=
ructor, while making `T t(something)` perform the equivalent of actual &quo=
t;default initialization&quot;.<br><br>I would say that the way to handle t=
his is to permit a user to define a constructor which performs default init=
ialization of the object&#39;s members. Like this:<br><br><div style=3D"bac=
kground-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:s=
olid;border-width:1px"><code><div><span style=3D"color:#008">struct</span><=
span style=3D"color:#000"> A<br></span><span style=3D"color:#660">{</span><=
span style=3D"color:#000"><br>=C2=A0 A</span><span style=3D"color:#660">()<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#800">/*non-t=
rivial default construction*/</span><span style=3D"color:#000"><br>=C2=A0 A=
</span><span style=3D"color:#660">(</span><span style=3D"color:#000">uninit=
ialize_t</span><span style=3D"color:#660">)</span><span style=3D"color:#000=
"> </span><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> =
default_init</span><span style=3D"color:#660">;</span><span style=3D"color:=
#000"><br></span><span style=3D"color:#660">};</span></div></code></div><br=
>The code generated for that constructor will default initialize its subobj=
ects, overriding all default member initializers and such. If one of the su=
bobjects is not trivially default constructible, then this function will no=
t be a trivial constructor. If one of the subobjects cannot undergo default=
 initialization (deleted default constructor, a reference, etc), this defin=
ition will be il-formed.<br></div></div></blockquote><div><br></div><div>Ye=
ah, that too, though I see no reason why it needs to be a new =3Ddefault_in=
it instead of just =3Ddefault.</div><div><br></div><div>Remember that A::A(=
) =3D default; is perfectly legal. Extending that to A::A(foo) =3D default =
or A::A(foo) : A() =3D default is a small step. The =3Ddefault basically tr=
anslates to &quot;ignore implicit supression if present and supply a trivia=
l empty body; if all other invoked member initializations, implicit or expl=
icit, are trivial, then this is trivial as well.&quot;</div><div><br></div>=
<div>=C2=A0 =C2=A0 class A {</div><div>=C2=A0 =C2=A0 =C2=A0 int x;</div><di=
v>=C2=A0 =C2=A0 public:</div><div>=C2=A0 =C2=A0 =C2=A0 A() =3D default; // =
trivial</div><div>=C2=A0 =C2=A0 =C2=A0 A(int x) : x(x) =3D default; // not =
trivial</div><div>=C2=A0 =C2=A0 =C2=A0 A(ignore_t) =3D default; // trivial<=
/div><div>=C2=A0 =C2=A0 =C2=A0 A(default_init) : A() =3D default; // trivia=
l</div><div>=C2=A0 =C2=A0 =C2=A0 A(int* p) : A(*p) =3D default; // not triv=
ial</div><div>=C2=A0 =C2=A0 };</div><div><br></div><blockquote class=3D"gma=
il_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid=
;padding-left: 1ex;"><div dir=3D"ltr"><div><br>I think this would work bett=
er for your needs. We keep `A a;` equivalent to `A a =3D default_init;`: th=
ey both call the default constructor, which in this case is non-trivial. Bu=
t `A a =3D uninitialize_t{};` will default initialize the members, effectiv=
ely doing nothing. It can be a trivial constructor, testable via `is_trivia=
lly_constructible&lt;A, uninitialize_t&gt;`. It will be a noexcept construc=
tor, so long as any constructors it calls are noexcept. And so forth.<br></=
div></div></blockquote><div><br></div><div>I agree that all works, and give=
n your proposal being formalized and accepted, is totally good. :)</div><di=
v>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"=
><div><br>In effect, the above declaration is like this:<br><br><div style=
=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-=
style:solid;border-width:1px"><code><div><span style=3D"color:#000">A</span=
><span style=3D"color:#660">(</span><span style=3D"color:#000">uninitialize=
_t</span><span style=3D"color:#660">)</span><span style=3D"color:#000"> bas=
e_classes</span><span style=3D"color:#660">(</span><span style=3D"color:#00=
0">default_init</span><span style=3D"color:#660">)...,</span><span style=3D=
"color:#000"> members</span><span style=3D"color:#660">(</span><span style=
=3D"color:#000">default_init</span><span style=3D"color:#660">)...</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#660">{}</span></div>=
</code></div><br>Except that the compiler is aware that this is what&#39;s =
going on and it can therefore optimize it away.<br><br>To do this, I believ=
e this means that `default_init` will now have to be a keyword, much like `=
nullptr` and its relationship to `std::nullptr_t`. Unless we can put specia=
l identifiers in the `=3D stuff` part of a function declaration.</div></div=
></blockquote><div><br></div><div>I don&#39;t think so at all. Trivialness =
doesn&#39;t require any new keywords or semantics; the only thing blocking =
it from being applicable to any function is the presence of the empty body =
and the fact that =3Ddefault can currently only be applied to compiler gene=
rator functions.</div><div><br></div><div>Automatic generation of type(std:=
:default_init_t) is one step necessary for your proposed syntax no matter w=
hat. Allowing =3Ddefault on any function body solves my use case _and_ comp=
letes your feature with no additional one-off semantics; two &quot;small&qu=
ot; features combine to satisfy both of our use cases. :)</div><div><br></d=
iv><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0class mytype {</=
font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0public:<=
/font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0=
mytype() =3D default;</font></div><div><font face=3D"courier new, monospace=
">=C2=A0 =C2=A0 =C2=A0// automatically generated:</font></div><div><font fa=
ce=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0mytype(std::default_init_=
t) : mytype() =3D default;</font></div><div><font face=3D"courier new, mono=
space">=C2=A0 =C2=A0};<br></font></div><div><font face=3D"courier new, mono=
space"><br></font></div><div><font face=3D"courier new, monospace">=C2=A0 =
=C2=A0class safesimd {</font></div><div><font face=3D"courier new, monospac=
e">=C2=A0 =C2=A0 =C2=A0float x, y;</font></div><div><font face=3D"courier n=
ew, monospace">=C2=A0 =C2=A0public:</font></div><div><font face=3D"courier =
new, monospace">=C2=A0 =C2=A0 =C2=A0safesimd() : x(0), y(0) {} // non-trivi=
al, safe defaults</font></div><div><font face=3D"courier new, monospace">=
=C2=A0 =C2=A0 =C2=A0safesimd(unitialized_t) =3D default; // trivial, member=
s default initialized</font></div><div><font face=3D"courier new, monospace=
"><br></font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0=
 =C2=A0// automatically generated:<br></font></div><div><font face=3D"couri=
er new, monospace">=C2=A0 =C2=A0 =C2=A0safesimd(std::default_init_t) : safe=
simd() =3D default;</font></div><div><font face=3D"courier new, monospace">=
=C2=A0 =C2=A0};</font></div><div><font face=3D"courier new, monospace"><br>=
</font></div><div>In short, I think we can get both what we want independen=
t of the disagreement, e.g. whether the default_init constructor is overrid=
able is immaterial to the tweaks I&#39;m suggesting. For reference though, =
the disagreement basically boils down to:<br></div><div><font face=3D"couri=
er new, monospace"><br></font></div><div><font face=3D"courier new, monospa=
ce">=C2=A0 =C2=A0class disagreement {</font></div><div><font face=3D"courie=
r new, monospace">=C2=A0 =C2=A0public:</font></div><div><font face=3D"couri=
er new, monospace">=C2=A0 =C2=A0 =C2=A0disagreement() =3D default;</font></=
div><div><font face=3D"courier new, monospace"><br></font></div><div><font =
face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0// user-supplied overri=
de:</font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =
=C2=A0disagreement(std::default_init_t) { /* fancy meta-programming or some=
thing */ }</font></div><div><font face=3D"courier new, monospace"><br></fon=
t></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0// o=
r maybe even deleted</font></div><div><span style=3D"font-family: &quot;cou=
rier new&quot;, monospace;">=C2=A0 =C2=A0 =C2=A0disagreement(std::default_i=
nit_t) =3D delete;</span></div><div><font face=3D"courier new, monospace">=
=C2=A0 =C2=A0};</font></div><div><br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/b851c076-a90b-446d-be90-bb832132f840%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/b851c076-a90b-446d-be90-bb832132f840=
%40isocpp.org</a>.<br />

------=_Part_160_1278212634.1482129808884--

------=_Part_159_2083619575.1482129808883--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 19 Dec 2016 08:45:11 -0800 (PST)
Raw View
------=_Part_1330_1558341502.1482165911671
Content-Type: multipart/alternative;
 boundary="----=_Part_1331_1003949396.1482165911671"

------=_Part_1331_1003949396.1482165911671
Content-Type: text/plain; charset=UTF-8



On Monday, December 19, 2016 at 1:43:29 AM UTC-5, Sean Middleditch wrote:
>
> On Saturday, December 17, 2016 at 8:26:26 AM UTC-8, Nicol Bolas wrote:
>>
>> Which makes me think: perhaps instead of making default_init_t
>>> *completely* magic we could instead loosen the rules for constructor to
>>> allow any constructor to have =default instead of a body. The compiler can
>>> then easily determine if the constructor is trivial or not via the existing
>>> rules. All types could then have a "magic" constructor
>>> foo::foo(std::default_init_t) : foo() = default; implicitly generated if
>>> the default constructor isn't deleted. This also makes the overload
>>> question I posed much simpler to answer since the answer becomes implied. I
>>> think the generality is a better design in (ahem 2) general, but in this
>>> case it also means existing code (like mine) using a similar type/trick can
>>> just replace their empty constructor bodies with =default to become
>>> trivial, just like we did with default constructors in C++11.
>>>
>>
>> I *really* don't like this idea.
>>
>> The whole point of this feature is to permit a user to default initialize
>> any type `T` by doing `T t = default_init;`. Therefore, that statement must
>> always be *equivalent* to `T t;`.
>>
>
> Here we'll disagree then. :)
>

But... that's the problem domain I outlined: I have some type T, which is
being initialized through some forwarded interface, and I want to invoke
default initialization on it. That's not the problem that your method
solves. It never actually invokes the rules of default initialization; you
merely get to call a constructor that maybe doesn't initialize the object's
data.

That's not the same thing. For reasons you'll see next:

The magic value approach sits very poorly with me. I'd prefer to minimize
> its impact on the language to the smallest possible degree. I believe your
> use case can be achieve with nothing more than introducing the
> automatically generated constructor _if_ there's also a way to note that
> forwarded constructors can inherit triviality... which my added suggestions
> provides (and that suggestion provides more use cases than just making your
> feature work, which implies that it has relatively high value so far as the
> difficulty-to-usefulness ratio goes).
>

OK, explain how I would do this without compiler magic:

vector<int> v;
v.emplace_back(std::default_init);

This statement is going to call `allocator_traits::construct(a, p,
std::default_init)`. Which will eventually perform `new(p)
int(std::default_init)`.

If `std::default_init_t` is a regular type, that's a compile error. The
only way to make this compile without compiler magic is to make
`std::default_init_t` implicitly convertible to a (presumably
default-initialized) value of any basic type. But that causes all kinds of
*other* problems.

So compiler magic is going to have to happen, one way or another.


> If you use this magic constructor method, users can now *override*
>> `default_init_t` initialization. That completely destroys the whole purpose
>> of the feature. `T t`; will always follow [dcl.init]/7, while `T t =
>> default_init;` is just like any other constructor call.
>>
>
> Unless of course that's what the author of the library wanted. Why
> shouldn't an expert library author be able to override the constructor?
> There are valid use cases to be able to override just about everything
> else, which is allowed. I don't think it's terribly important to be able to
> override it, but I'm not sure what you're really buying in real-world
> utility by adding special cases here.
>

The utility is that the code does what it says. It performs default
initialization, as that is defined in the standard. Not "whatever form of
initialization the user has substituted for `default_init`.

Otherwise, calling it "default_init" is a lie. It's merely "user_init",
except that it's something supplied by the standard library.

I get what you're wanting. You want `T t` to call a default constructor,
>> while making `T t(something)` perform the equivalent of actual "default
>> initialization".
>>
>> I would say that the way to handle this is to permit a user to define a
>> constructor which performs default initialization of the object's members.
>> Like this:
>>
>> struct A
>> {
>>   A() /*non-trivial default construction*/
>>   A(uninitialize_t) = default_init;
>> };
>>
>> The code generated for that constructor will default initialize its
>> subobjects, overriding all default member initializers and such. If one of
>> the subobjects is not trivially default constructible, then this function
>> will not be a trivial constructor. If one of the subobjects cannot undergo
>> default initialization (deleted default constructor, a reference, etc),
>> this definition will be il-formed.
>>
>
> Yeah, that too, though I see no reason why it needs to be a new
> =default_init instead of just =default.
>
> Remember that A::A() = default; is perfectly legal. Extending that to
> A::A(foo) = default or A::A(foo) : A() = default is a small step. The
> =default basically translates to "ignore implicit supression if present and
> supply a trivial empty body; if all other invoked member initializations,
> implicit or explicit, are trivial, then this is trivial as well."
>

But that's not what `= default` means. Defaulting a copy constructor does
not "supply a trivial empty body"; it supplies a *real* function definition
that may or may not be trivial depending on what that definition has to do.

In any case, I don't even what `A::A(foo) : A() = default` is supposed to
mean. You can't default a function that has a definition. This constructor
calls another constructor, so it has a definition. But `= default` is
supposed to supply the *entire* definition. So... what exactly is this
doing? Is it calling a constructor, or is it doing something default? Or is
it somehow doing both?

The reason to go with a new term rather than `= default` is so that it can
have different semantics from `= default`. If you `= default` a default
constructor, the default member initializers are still invoked. Whereas if
you `= default_init` it, then the DMI's are *ignored*.

Furthermore, if you `= default` a default constructor, but one of the
subobjects cannot be default constructed, then the default constructor is
internally `= delete`d. That's not the behavior we want when using `=
default_init`; if the type cannot be default initialized, then the code
should be ill-formed.

There's a difference between these two classes:

class A
{
public:
  A() = default_init;

private:
  int i = 20;
};

class B
{
public:
  B() = default;

private:
  int i = 20;
};

`B` will always initialize its member, while `A()` will leave it
uninitialized (though this will be true even in value initialization, so
it's probably not a good idea to slap `= default_init` on a default
constructor). This is asking for a different kind of code generation. So
you should need to use a new syntax for that.

Now, perhaps `= default_init` is the wrong term. What you're really
creating is an *uninitializing* constructor: a constructor that in theory
performs no initialization. The only initialization it may perform is
calling default constructors for subobjects that aren't trivially default
constructible. But it would not invoke default member initializers.

I think. I'm still fairly up in the air about what the semantics of these
things should be (though they do need to be *able* to be different from `=
default`). Maybe they should fail to compile if any subobjects are not
trivially default constructible. Maybe it should be `= trivial`.


>> In effect, the above declaration is like this:
>>
>> A(uninitialize_t) base_classes(default_init)..., members(default_init)...
>> {}
>>
>> Except that the compiler is aware that this is what's going on and it can
>> therefore optimize it away.
>>
>> To do this, I believe this means that `default_init` will now have to be
>> a keyword, much like `nullptr` and its relationship to `std::nullptr_t`.
>> Unless we can put special identifiers in the `= stuff` part of a function
>> declaration.
>>
>
> I don't think so at all. Trivialness doesn't require any new keywords or
> semantics; the only thing blocking it from being applicable to any function
> is the presence of the empty body and the fact that =default can currently
> only be applied to compiler generator functions.
>
> Automatic generation of type(std::default_init_t) is one step necessary
> for your proposed syntax no matter what.
>

It is not necessary at all. Remember, `default_init_t` is something the
initialization parts of the standard have to expressly look for. So there
doesn't have to be such a constructor. After all, `int
i(std::default_init)` needs to work; otherwise, this feature isn't doing
its job.

Since you're going to have to change [dcl.init] anyway, it's much easier to
insert the following rule between 17.2 and 17.3:

> 17.3.new: if the initializer is a single expression of type
`std::default_init_t`, then the object is default-initialized.

Your way would require inserting an *almost identical* rule, with the only
difference being that the rule would only apply to non-class types. Then
you have to insert a bunch of stuff in Chapter 12 about this new special
member function.

It's much simpler for the standard to just say that all types treat
initialization from `std::default_init_t` in the same way.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/93bfc7e9-265b-4f6f-bf02-8a38d24675bf%40isocpp.org.

------=_Part_1331_1003949396.1482165911671
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Monday, December 19, 2016 at 1:43:29 AM UTC-5, =
Sean Middleditch wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0=
;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div di=
r=3D"ltr">On Saturday, December 17, 2016 at 8:26:26 AM UTC-8, Nicol Bolas w=
rote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;=
border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div dir=3D"ltr"><div>Which makes me think: perh=
aps instead of making default_init_t *completely* magic we could instead lo=
osen the rules for constructor to allow any constructor to have =3Ddefault =
instead of a body. The compiler can then easily determine if the constructo=
r is trivial or not via the existing rules. All types could then have a &qu=
ot;magic&quot; constructor foo::foo(std::default_init_t) : foo() =3D defaul=
t; implicitly generated if the default constructor isn&#39;t deleted. This =
also makes the overload question I posed much simpler to answer since the a=
nswer becomes implied. I think the generality is a better design in (ahem 2=
) general, but in this case it also means existing code (like mine) using a=
 similar type/trick can just replace their empty constructor bodies with =
=3Ddefault to become trivial, just like we did with default constructors in=
 C++11.<br></div></div></blockquote><div><br>I <i>really</i> don&#39;t like=
 this idea.<br><br>The whole point of this feature is to permit a user to d=
efault initialize any type `T` by doing `T t =3D default_init;`. Therefore,=
 that statement must always be <i>equivalent</i> to `T t;`.<br></div></div>=
</blockquote><div><br></div><div>Here we&#39;ll disagree then. :)</div></di=
v></blockquote><div><br>But... that&#39;s the problem domain I outlined: I =
have some type T, which is being initialized through some forwarded interfa=
ce, and I want to invoke default initialization on it. That&#39;s not the p=
roblem that your method solves. It never actually invokes the rules of defa=
ult initialization; you merely get to call a constructor that maybe doesn&#=
39;t initialize the object&#39;s data.<br><br>That&#39;s not the same thing=
.. For reasons you&#39;ll see next:<br><br></div><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;"><div dir=3D"ltr"><div></div><div>The magic value approach=
 sits very poorly with me. I&#39;d prefer to minimize its impact on the lan=
guage to the smallest possible degree. I believe your use case can be achie=
ve with nothing more than introducing the automatically generated construct=
or _if_ there&#39;s also a way to note that forwarded constructors can inhe=
rit triviality... which my added suggestions provides (and that suggestion =
provides more use cases than just making your feature work, which implies t=
hat it has relatively high value so far as the difficulty-to-usefulness rat=
io goes).</div></div></blockquote><div><br>OK, explain how I would do this =
without compiler magic:<br><br><div style=3D"background-color: rgb(250, 250=
, 250); border-color: rgb(187, 187, 187); border-style: solid; border-width=
: 1px; overflow-wrap: break-word;" class=3D"prettyprint"><code class=3D"pre=
ttyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;" class=
=3D"styled-by-prettify">vector</span><span style=3D"color: #080;" class=3D"=
styled-by-prettify">&lt;int&gt;</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> v</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br>v</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">emplace_ba=
ck</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">std</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">default_init</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">);</span></div></code></div>=
<br>This statement is going to call `allocator_traits::construct(a, p, std:=
:default_init)`. Which will eventually perform `new(p) int(std::default_ini=
t)`.<br><br>If `std::default_init_t` is a regular type, that&#39;s a compil=
e error. The only way to make this compile without compiler magic is to mak=
e `std::default_init_t` implicitly convertible to a (presumably default-ini=
tialized) value of any basic type. But that causes all kinds of <i>other</i=
> problems.<br><br>So compiler magic is going to have to happen, one way or=
 another.<br>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:=
 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div =
dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left=
:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>I=
f you use this magic constructor method, users can now <i>override</i> `def=
ault_init_t` initialization. That completely destroys the whole purpose of =
the feature. `T t`; will always follow [dcl.init]/7, while `T t =3D default=
_init;` is just like any other constructor call.<br></div></div></blockquot=
e><div><br></div><div>Unless of course that&#39;s what the author of the li=
brary wanted. Why shouldn&#39;t an expert library author be able to overrid=
e the constructor? There are valid use cases to be able to override just ab=
out everything else, which is allowed. I don&#39;t think it&#39;s terribly =
important to be able to override it, but I&#39;m not sure what you&#39;re r=
eally buying in real-world utility by adding special cases here.</div></div=
></blockquote><div><br>The utility is that the code does what it says. It p=
erforms default initialization, as that is defined in the standard. Not &qu=
ot;whatever form of initialization the user has substituted for `default_in=
it`.<br><br>Otherwise, calling it &quot;default_init&quot; is a lie. It&#39=
;s merely &quot;user_init&quot;, except that it&#39;s something supplied by=
 the standard library.<br><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin:0;=
margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"=
ltr"><div>I get what you&#39;re wanting. You want `T t` to call a default c=
onstructor, while making `T t(something)` perform the equivalent of actual =
&quot;default initialization&quot;.<br><br>I would say that the way to hand=
le this is to permit a user to define a constructor which performs default =
initialization of the object&#39;s members. Like this:<br><br><div style=3D=
"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-sty=
le:solid;border-width:1px"><code><div><span style=3D"color:#008">struct</sp=
an><span style=3D"color:#000"> A<br></span><span style=3D"color:#660">{</sp=
an><span style=3D"color:#000"><br>=C2=A0 A</span><span style=3D"color:#660"=
>()</span><span style=3D"color:#000"> </span><span style=3D"color:#800">/*n=
on-trivial default construction*/</span><span style=3D"color:#000"><br>=C2=
=A0 A</span><span style=3D"color:#660">(</span><span style=3D"color:#000">u=
ninitialize_t</span><span style=3D"color:#660">)</span><span style=3D"color=
:#000"> </span><span style=3D"color:#660">=3D</span><span style=3D"color:#0=
00"> default_init</span><span style=3D"color:#660">;</span><span style=3D"c=
olor:#000"><br></span><span style=3D"color:#660">};</span></div></code></di=
v><br>The code generated for that constructor will default initialize its s=
ubobjects, overriding all default member initializers and such. If one of t=
he subobjects is not trivially default constructible, then this function wi=
ll not be a trivial constructor. If one of the subobjects cannot undergo de=
fault initialization (deleted default constructor, a reference, etc), this =
definition will be il-formed.<br></div></div></blockquote><div><br></div><d=
iv>Yeah, that too, though I see no reason why it needs to be a new =3Ddefau=
lt_init instead of just =3Ddefault.</div><div><br></div><div>Remember that =
A::A() =3D default; is perfectly legal. Extending that to A::A(foo) =3D def=
ault or A::A(foo) : A() =3D default is a small step. The =3Ddefault basical=
ly translates to &quot;ignore implicit supression if present and supply a t=
rivial empty body; if all other invoked member initializations, implicit or=
 explicit, are trivial, then this is trivial as well.&quot;</div></div></bl=
ockquote><div><br>But that&#39;s not what `=3D default` means. Defaulting a=
 copy constructor does not &quot;supply a trivial empty body&quot;; it supp=
lies a <i>real</i> function definition that may or may not be trivial depen=
ding on what that definition has to do.<br><br>In any case, I don&#39;t eve=
n what `A::A(foo) : A() =3D default` is supposed to mean. You can&#39;t def=
ault a function that has a definition. This constructor calls another const=
ructor, so it has a definition. But `=3D default` is supposed to supply the=
 <i>entire</i> definition. So... what exactly is this doing? Is it calling =
a constructor, or is it doing something default? Or is it somehow doing bot=
h?<br><br>The reason to go with a new term rather than `=3D default` is so =
that it can have different semantics from `=3D default`. If you `=3D defaul=
t` a default constructor, the default member initializers are still invoked=
.. Whereas if you `=3D default_init` it, then the DMI&#39;s are <i>ignored</=
i>.<br><br>Furthermore, if you `=3D default` a default constructor, but one=
 of the subobjects cannot be default constructed, then the default construc=
tor is internally `=3D delete`d. That&#39;s not the behavior we want when u=
sing `=3D default_init`; if the type cannot be default initialized, then th=
e code should be ill-formed.<br><br>There&#39;s a difference between these =
two classes:<br><br><div style=3D"background-color: rgb(250, 250, 250); bor=
der-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; over=
flow-wrap: break-word;" class=3D"prettyprint"><code class=3D"prettyprint"><=
div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">class</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> A<br></span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">public</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 A</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">()</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> default_init</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">private</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">:</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br>=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-=
by-prettify">int</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> i </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #066;" class=3D"styled-by-prettify">20</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">class</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> B<br></span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">public</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =
B</span><span style=3D"color: #660;" class=3D"styled-by-prettify">()</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">default</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br><br></span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">private</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">:</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br>=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">int</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> i </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
 style=3D"color: #066;" class=3D"styled-by-prettify">20</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">};</span></div></code></div><br>`B` will al=
ways initialize its member, while `A()` will leave it uninitialized (though=
 this will be true even in value initialization, so it&#39;s probably not a=
 good idea to slap `=3D default_init` on a default constructor). This is as=
king for a different kind of code generation. So you should need to use a n=
ew syntax for that.<br><br>Now, perhaps `=3D default_init` is the wrong ter=
m. What you&#39;re really creating is an <i>uninitializing</i> constructor:=
 a constructor that in theory performs no initialization. The only initiali=
zation it may perform is calling default constructors for subobjects that a=
ren&#39;t trivially default constructible. But it would not invoke default =
member initializers.<br><br>I think. I&#39;m still fairly up in the air abo=
ut what the semantics of these things should be (though they do need to be =
<i>able</i> to be different from `=3D default`). Maybe they should fail to =
compile if any subobjects are not trivially default constructible. Maybe it=
 should be `=3D trivial`.<br><br></div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div dir=3D"ltr"><div></div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div dir=3D"ltr"><div><br>In effect, the above declaration is like this:<=
br><br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187=
,187,187);border-style:solid;border-width:1px"><code><div><span style=3D"co=
lor:#000">A</span><span style=3D"color:#660">(</span><span style=3D"color:#=
000">uninitialize_t</span><span style=3D"color:#660">)</span><span style=3D=
"color:#000"> base_classes</span><span style=3D"color:#660">(</span><span s=
tyle=3D"color:#000">default_init</span><span style=3D"color:#660">)...,</sp=
an><span style=3D"color:#000"> members</span><span style=3D"color:#660">(</=
span><span style=3D"color:#000">default_init</span><span style=3D"color:#66=
0">)...</span><span style=3D"color:#000"> </span><span style=3D"color:#660"=
>{}</span></div></code></div><br>Except that the compiler is aware that thi=
s is what&#39;s going on and it can therefore optimize it away.<br><br>To d=
o this, I believe this means that `default_init` will now have to be a keyw=
ord, much like `nullptr` and its relationship to `std::nullptr_t`. Unless w=
e can put special identifiers in the `=3D stuff` part of a function declara=
tion.</div></div></blockquote><div><br></div><div>I don&#39;t think so at a=
ll. Trivialness doesn&#39;t require any new keywords or semantics; the only=
 thing blocking it from being applicable to any function is the presence of=
 the empty body and the fact that =3Ddefault can currently only be applied =
to compiler generator functions.</div><div><br></div><div>Automatic generat=
ion of type(std::default_init_t) is one step necessary for your proposed sy=
ntax no matter what.</div></div></blockquote><div><br>It is not necessary a=
t all. Remember, `default_init_t` is something the initialization parts of =
the standard have to expressly look for. So there doesn&#39;t have to be su=
ch a constructor. After all, `int i(std::default_init)` needs to work; othe=
rwise, this feature isn&#39;t doing its job.<br><br>Since you&#39;re going =
to have to change [dcl.init] anyway, it&#39;s much easier to insert the fol=
lowing rule between 17.2 and 17.3:<br><br>&gt; 17.3.new: if the initializer=
 is a single expression of type `std::default_init_t`, then the object is d=
efault-initialized.<br><br>Your way would require inserting an <i>almost id=
entical</i> rule, with the only difference being that the rule would only a=
pply to non-class types. Then you have to insert a bunch of stuff in Chapte=
r 12 about this new special member function.<br><br>It&#39;s much simpler f=
or the standard to just say that all types treat initialization from `std::=
default_init_t` in the same way.</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/93bfc7e9-265b-4f6f-bf02-8a38d24675bf%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/93bfc7e9-265b-4f6f-bf02-8a38d24675bf=
%40isocpp.org</a>.<br />

------=_Part_1331_1003949396.1482165911671--

------=_Part_1330_1558341502.1482165911671--

.


Author: Sean Middleditch <sean.middleditch@gmail.com>
Date: Sun, 25 Dec 2016 14:07:37 -0800 (PST)
Raw View
------=_Part_3305_1083689784.1482703657491
Content-Type: multipart/alternative;
 boundary="----=_Part_3306_1865747843.1482703657492"

------=_Part_3306_1865747843.1482703657492
Content-Type: text/plain; charset=UTF-8

On Monday, December 19, 2016 at 8:45:11 AM UTC-8, Nicol Bolas wrote:
>
> On Monday, December 19, 2016 at 1:43:29 AM UTC-5, Sean Middleditch wrote:
>>
>> On Saturday, December 17, 2016 at 8:26:26 AM UTC-8, Nicol Bolas wrote:
>>>
>>> Which makes me think: perhaps instead of making default_init_t
>>>> *completely* magic we could instead loosen the rules for constructor to
>>>> allow any constructor to have =default instead of a body. The compiler can
>>>> then easily determine if the constructor is trivial or not via the existing
>>>> rules. All types could then have a "magic" constructor
>>>> foo::foo(std::default_init_t) : foo() = default; implicitly generated if
>>>> the default constructor isn't deleted. This also makes the overload
>>>> question I posed much simpler to answer since the answer becomes implied. I
>>>> think the generality is a better design in (ahem 2) general, but in this
>>>> case it also means existing code (like mine) using a similar type/trick can
>>>> just replace their empty constructor bodies with =default to become
>>>> trivial, just like we did with default constructors in C++11.
>>>>
>>>
>>> I *really* don't like this idea.
>>>
>>> The whole point of this feature is to permit a user to default
>>> initialize any type `T` by doing `T t = default_init;`. Therefore, that
>>> statement must always be *equivalent* to `T t;`.
>>>
>>
>> Here we'll disagree then. :)
>>
>
> But... that's the problem domain I outlined: I have some type T, which is
> being initialized through some forwarded interface, and I want to invoke
> default initialization on it. That's not the problem that your method
> solves. It never actually invokes the rules of default initialization; you
> merely get to call a constructor that maybe doesn't initialize the object's
> data.
>

I get it's not the same. What I'm getting at is that you can have two
"small" features combine into multiple bigger features, instead of needing
to define two separate big features. :)


>
> That's not the same thing. For reasons you'll see next:
>
> The magic value approach sits very poorly with me. I'd prefer to minimize
>> its impact on the language to the smallest possible degree. I believe your
>> use case can be achieve with nothing more than introducing the
>> automatically generated constructor _if_ there's also a way to note that
>> forwarded constructors can inherit triviality... which my added suggestions
>> provides (and that suggestion provides more use cases than just making your
>> feature work, which implies that it has relatively high value so far as the
>> difficulty-to-usefulness ratio goes).
>>
>
> OK, explain how I would do this without compiler magic:
>
> vector<int> v;
> v.emplace_back(std::default_init);
>
> This statement is going to call `allocator_traits::construct(a, p,
> std::default_init)`. Which will eventually perform `new(p)
> int(std::default_init)`.
>
> If `std::default_init_t` is a regular type, that's a compile error. The
> only way to make this compile without compiler magic is to make
> `std::default_init_t` implicitly convertible to a (presumably
> default-initialized) value of any basic type. But that causes all kinds of
> *other* problems.
>
> So compiler magic is going to have to happen, one way or another.
>

Certainly, which I acknowledged - the "minimal" magic would be to provide a
std::default_init_t type for all types (built-in or otherwise), but
literally no other special rules regarding the constructor signature. This
isn't even a huge deal of magic since we already have standard support for
compiler-generated constructors (default, copy, and move, specifically).
With the =default feature, the definition of this generated
std::default_init_t is also pretty much solved without needing to add
additional language for what default_init_t does into the standard's
grammar definition.

e.g., less magic.


>
>
>> If you use this magic constructor method, users can now *override*
>>> `default_init_t` initialization. That completely destroys the whole purpose
>>> of the feature. `T t`; will always follow [dcl.init]/7, while `T t =
>>> default_init;` is just like any other constructor call.
>>>
>>
>> Unless of course that's what the author of the library wanted. Why
>> shouldn't an expert library author be able to override the constructor?
>> There are valid use cases to be able to override just about everything
>> else, which is allowed. I don't think it's terribly important to be able to
>> override it, but I'm not sure what you're really buying in real-world
>> utility by adding special cases here.
>>
>
> The utility is that the code does what it says. It performs default
> initialization, as that is defined in the standard. Not "whatever form of
> initialization the user has substituted for `default_init`.
>

Fair. I'm not convinced that's all that important given all the other
overload magic tricks users can do, though.

If you are sure that there must be a non-overloadable way of specifying
default values, then my bike-shedding preference would be to avoid a magic
library type for the purpose, e.g. maybe to just allow `default` as an
expression and to make the language have specific rules that the
constructor A(default) is equivalent to A(). It would make your proposal
feel more like nullptr's place in the language and less like
std::initializer_list (and yeah, I'm salty still about the later and
consider it a language wart, but that's me).

That also makes it a lot more clear and non-magic about why it can't be
overloaded: it's much clearer that a declaration A::A(default) is just a
synonym for A::A() the same way that f(void) is a synonym for f(). I like
consistent, clear, and obvious grammar. :)


> I get what you're wanting. You want `T t` to call a default constructor,
> while making `T t(something)` perform the equivalent of actual "default
> initialization".
>

>>> I would say that the way to handle this is to permit a user to define a
>>> constructor which performs default initialization of the object's members.
>>> Like this:
>>>
>>> struct A
>>> {
>>>   A() /*non-trivial default construction*/
>>>   A(uninitialize_t) = default_init;
>>> };
>>>
>>> The code generated for that constructor will default initialize its
>>> subobjects, overriding all default member initializers and such. If one of
>>> the subobjects is not trivially default constructible, then this function
>>> will not be a trivial constructor. If one of the subobjects cannot undergo
>>> default initialization (deleted default constructor, a reference, etc),
>>> this definition will be il-formed.
>>>
>>
>> Yeah, that too, though I see no reason why it needs to be a new
>> =default_init instead of just =default.
>>
>> Remember that A::A() = default; is perfectly legal. Extending that to
>> A::A(foo) = default or A::A(foo) : A() = default is a small step. The
>> =default basically translates to "ignore implicit supression if present and
>> supply a trivial empty body; if all other invoked member initializations,
>> implicit or explicit, are trivial, then this is trivial as well."
>>
>
> But that's not what `= default` means. Defaulting a copy constructor does
> not "supply a trivial empty body"; it supplies a *real* function
> definition that may or may not be trivial depending on what that definition
> has to do.
>

Well understood, and I've not (intentionally) tried to imply anything else.
:)


> The reason to go with a new term rather than `= default` is so that it can
> have different semantics from `= default`. If you `= default` a default
> constructor, the default member initializers are still invoked. Whereas if
> you `= default_init` it, then the DMI's are *ignored*.
>

I think that's particularly dangerous.

It's a very muddled place between `A::A() = default` and `A::A() =
default_init` having wildly different and potentially disastrously
different semantics.

Explicit beats implicit. If I want to override a DMI, the language already
provides a way to do so: supply an initializer in the constructor. That's
the place where I should opt in (on a member-by-member basis) which
initializers to suppress.

A::A() : x(default_init) = meow_whatever_allows_this_to_be_trivial_meow;

I'm not married to =default but it seems the best choice, since it already
has the desired meaning and semantics, only it's just not allowed outside
of a handful of limited places. This is similar to the comparison
operations being discussed that allow them to be =default even though the
generated body will be something specific to the function being defaulted.

In this case, =default on a constructor - other than the copy or move
constructors - would just mean "an empty body that may be trivial iff the
member and base initializers are trivial." Which is at its core the exact
meaning you get today with =default on the default constructor, so it's
consistent and already well-understood and doesn't require new concepts or
keywords or rules to be taught - it's just a generalization of =default. :)


>
> Furthermore, if you `= default` a default constructor, but one of the
> subobjects cannot be default constructed, then the default constructor is
> internally `= delete`d. That's not the behavior we want when using `=
> default_init`; if the type cannot be default initialized, then the code
> should be ill-formed.
>

I'm missing the distinction here, I think.


>
> There's a difference between these two classes:
>
> class A
> {
> public:
>   A() = default_init;
>
> private:
>   int i = 20;
> };
>
> class B
> {
> public:
>   B() = default;
>
> private:
>   int i = 20;
> };
>
> `B` will always initialize its member, while `A()` will leave it
> uninitialized (though this will be true even in value initialization, so
> it's probably not a good idea to slap `= default_init` on a default
> constructor). This is asking for a different kind of code generation. So
> you should need to use a new syntax for that.
>

A could also just be given using my suggestion with something like:

class A
{
public:
  A() : i{std::default_init} = default; // A() has an empty body and only
trivial member initialization, so it's trivial

private:
  int i = 20; // essentially pointless NSDMI for this type
};


The default constructor for A would then override its i member initializer
to be uninitialized and allow the body to be generated by the compiler and
hence detected in this case as being trivial.


> Now, perhaps `= default_init` is the wrong term. What you're really
> creating is an *uninitializing* constructor: a constructor that in theory
> performs no initialization. The only initialization it may perform is
> calling default constructors for subobjects that aren't trivially default
> constructible. But it would not invoke default member initializers.
>
> I think. I'm still fairly up in the air about what the semantics of these
> things should be (though they do need to be *able* to be different from
> `= default`). Maybe they should fail to compile if any subobjects are not
> trivially default constructible. Maybe it should be `= trivial`.
>

I'm leaning towards =default because the idea isn't to be _specifically for
trivial objects_. Again, I can't stress enough that I want avoid one-off
features and aim for generality.

My suggestion is to be a general facility that is a building block for your
default_init and for uninitialized construction and for making certain
meta-programming Just Work(tm) as trivial when and if the various SFINAE,
Concepts, and specializations may require it. Consider your example
previously, but replace the integer member with something "trickier":

template <class T>
class A {
public:
  A(C<T> i) : m(i.foo()) = default; // this may or may not be trivial,
dependent on B(decltype(C<T>::foo()))
                                    // being trivial, but the body {} will
never be trivial


private:
  B<T> m;

In the above type with C++ today or with just your default_init, there is
no way to define A::A that will ever be trivial, even if the member
initialize it invokes is trivial (say, C<T>::foo() might return a B<T>
const& which invokes a trivial copy constructor. That's because today, you
must put a body {} on the definition, which the compiler will never ever
interpret as trivial. That's a language limitation that has absolutely
nothing to do with either your or my user case and yet would be corrected
with my suggestion. Generality is good. :)


In my personal and probably unimportant opinion a very key design goal for
languages is to aim for small reuable bits of functionality instead of
large chunks of purpose-built functionality. It's composable and emergent
rather than rigid and limited.


> Since you're going to have to change [dcl.init] anyway, it's much easier
> to insert the following rule between 17.2 and 17.3:
>
> > 17.3.new: if the initializer is a single expression of type
> `std::default_init_t`, then the object is default-initialized.
>
> Your way would require inserting an *almost identical* rule, with the
> only difference being that the rule would only apply to non-class types.
> Then you have to insert a bunch of stuff in Chapter 12 about this new
> special member function.
>
> It's much simpler for the standard to just say that all types treat
> initialization from `std::default_init_t` in the same way.
>

That actually is a nice point that does counter-balance away some of my
concerns nicely. :)

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/3c0ceb25-43ac-478d-8794-6e37e4784cc7%40isocpp.org.

------=_Part_3306_1865747843.1482703657492
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Monday, December 19, 2016 at 8:45:11 AM UTC-8, Nicol Bo=
las wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On =
Monday, December 19, 2016 at 1:43:29 AM UTC-5, Sean Middleditch wrote:<bloc=
kquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-lef=
t:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On Saturday, December 1=
7, 2016 at 8:26:26 AM UTC-8, Nicol Bolas wrote:<blockquote class=3D"gmail_q=
uote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddin=
g-left:1ex"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div d=
ir=3D"ltr"><div>Which makes me think: perhaps instead of making default_ini=
t_t *completely* magic we could instead loosen the rules for constructor to=
 allow any constructor to have =3Ddefault instead of a body. The compiler c=
an then easily determine if the constructor is trivial or not via the exist=
ing rules. All types could then have a &quot;magic&quot; constructor foo::f=
oo(std::default_init_t) : foo() =3D default; implicitly generated if the de=
fault constructor isn&#39;t deleted. This also makes the overload question =
I posed much simpler to answer since the answer becomes implied. I think th=
e generality is a better design in (ahem 2) general, but in this case it al=
so means existing code (like mine) using a similar type/trick can just repl=
ace their empty constructor bodies with =3Ddefault to become trivial, just =
like we did with default constructors in C++11.<br></div></div></blockquote=
><div><br>I <i>really</i> don&#39;t like this idea.<br><br>The whole point =
of this feature is to permit a user to default initialize any type `T` by d=
oing `T t =3D default_init;`. Therefore, that statement must always be <i>e=
quivalent</i> to `T t;`.<br></div></div></blockquote><div><br></div><div>He=
re we&#39;ll disagree then. :)</div></div></blockquote><div><br>But... that=
&#39;s the problem domain I outlined: I have some type T, which is being in=
itialized through some forwarded interface, and I want to invoke default in=
itialization on it. That&#39;s not the problem that your method solves. It =
never actually invokes the rules of default initialization; you merely get =
to call a constructor that maybe doesn&#39;t initialize the object&#39;s da=
ta.<br></div></div></blockquote><div><br></div><div>I get it&#39;s not the =
same. What I&#39;m getting at is that you can have two &quot;small&quot; fe=
atures combine into multiple bigger features, instead of needing to define =
two separate big features. :)</div><div>=C2=A0<br></div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br>That&#39;s not the sa=
me thing. For reasons you&#39;ll see next:<br><br></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr"><div></div><div>The magic value app=
roach sits very poorly with me. I&#39;d prefer to minimize its impact on th=
e language to the smallest possible degree. I believe your use case can be =
achieve with nothing more than introducing the automatically generated cons=
tructor _if_ there&#39;s also a way to note that forwarded constructors can=
 inherit triviality... which my added suggestions provides (and that sugges=
tion provides more use cases than just making your feature work, which impl=
ies that it has relatively high value so far as the difficulty-to-usefulnes=
s ratio goes).</div></div></blockquote><div><br>OK, explain how I would do =
this without compiler magic:<br><br><div style=3D"background-color:rgb(250,=
250,250);border-color:rgb(187,187,187);border-style:solid;border-width:1px"=
><code><div><span style=3D"color:#000">vector</span><span style=3D"color:#0=
80">&lt;int&gt;</span><span style=3D"color:#000"> v</span><span style=3D"co=
lor:#660">;</span><span style=3D"color:#000"><br>v</span><span style=3D"col=
or:#660">.</span><span style=3D"color:#000">emplace_back</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">std</span><span style=3D=
"color:#660">::</span><span style=3D"color:#000">default_<wbr>init</span><s=
pan style=3D"color:#660">);</span></div></code></div><br>This statement is =
going to call `allocator_traits::construct(<wbr>a, p, std::default_init)`. =
Which will eventually perform `new(p) int(std::default_init)`.<br><br>If `s=
td::default_init_t` is a regular type, that&#39;s a compile error. The only=
 way to make this compile without compiler magic is to make `std::default_i=
nit_t` implicitly convertible to a (presumably default-initialized) value o=
f any basic type. But that causes all kinds of <i>other</i> problems.<br><b=
r>So compiler magic is going to have to happen, one way or another.<br></di=
v></div></blockquote><div><br></div><div>Certainly, which I acknowledged - =
the &quot;minimal&quot; magic would be to provide a std::default_init_t typ=
e for all types (built-in or otherwise), but literally no other special rul=
es regarding the constructor signature. This isn&#39;t even a huge deal of =
magic since we already have standard support for compiler-generated constru=
ctors (default, copy, and move, specifically). With the =3Ddefault feature,=
 the definition of this generated std::default_init_t is also pretty much s=
olved without needing to add additional language for what default_init_t do=
es into the standard&#39;s grammar definition.</div><div><br></div><div>e.g=
.., less magic.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" styl=
e=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left:=
 1ex;"><div dir=3D"ltr"><div>=C2=A0</div><blockquote class=3D"gmail_quote" =
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left=
:1ex"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin:0;=
margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"=
ltr"><div>If you use this magic constructor method, users can now <i>overri=
de</i> `default_init_t` initialization. That completely destroys the whole =
purpose of the feature. `T t`; will always follow [dcl.init]/7, while `T t =
=3D default_init;` is just like any other constructor call.<br></div></div>=
</blockquote><div><br></div><div>Unless of course that&#39;s what the autho=
r of the library wanted. Why shouldn&#39;t an expert library author be able=
 to override the constructor? There are valid use cases to be able to overr=
ide just about everything else, which is allowed. I don&#39;t think it&#39;=
s terribly important to be able to override it, but I&#39;m not sure what y=
ou&#39;re really buying in real-world utility by adding special cases here.=
</div></div></blockquote><div><br>The utility is that the code does what it=
 says. It performs default initialization, as that is defined in the standa=
rd. Not &quot;whatever form of initialization the user has substituted for =
`default_init`.<br></div></div></blockquote><div><br></div><div>Fair. I&#39=
;m not convinced that&#39;s all that important given all the other overload=
 magic tricks users can do, though.</div><div><br></div><div>If you are sur=
e that there must be a non-overloadable way of specifying default values, t=
hen my bike-shedding preference would be to avoid a magic library type for =
the purpose, e.g. maybe to just allow `default` as an expression and to mak=
e the language have specific rules that the constructor A(default) is equiv=
alent to A(). It would make your proposal feel more like nullptr&#39;s plac=
e in the language and less like std::initializer_list (and yeah, I&#39;m sa=
lty still about the later and consider it a language wart, but that&#39;s m=
e).<br></div><div><br></div><div>That also makes it a lot more clear and no=
n-magic about why it can&#39;t be overloaded: it&#39;s much clearer that a =
declaration A::A(default) is just a synonym for A::A() the same way that f(=
void) is a synonym for f(). I like consistent, clear, and obvious grammar. =
:)</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:=
 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div =
dir=3D"ltr"><div>I get what you&#39;re wanting. You want `T t` to call a de=
fault constructor, while making `T t(something)` perform the equivalent of =
actual &quot;default initialization&quot;.<br></div></div></blockquote><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:=
1ex"><div dir=3D"ltr"><div><br>I would say that the way to handle this is t=
o permit a user to define a constructor which performs default initializati=
on of the object&#39;s members. Like this:<br><br><div style=3D"background-=
color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;bor=
der-width:1px"><code><div><span style=3D"color:#008">struct</span><span sty=
le=3D"color:#000"> A<br></span><span style=3D"color:#660">{</span><span sty=
le=3D"color:#000"><br>=C2=A0 A</span><span style=3D"color:#660">()</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#800">/*non-trivial d=
efault construction*/</span><span style=3D"color:#000"><br>=C2=A0 A</span><=
span style=3D"color:#660">(</span><span style=3D"color:#000">uninitialize_t=
</span><span style=3D"color:#660">)</span><span style=3D"color:#000"> </spa=
n><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> default_=
init</span><span style=3D"color:#660">;</span><span style=3D"color:#000"><b=
r></span><span style=3D"color:#660">};</span></div></code></div><br>The cod=
e generated for that constructor will default initialize its subobjects, ov=
erriding all default member initializers and such. If one of the subobjects=
 is not trivially default constructible, then this function will not be a t=
rivial constructor. If one of the subobjects cannot undergo default initial=
ization (deleted default constructor, a reference, etc), this definition wi=
ll be il-formed.<br></div></div></blockquote><div><br></div><div>Yeah, that=
 too, though I see no reason why it needs to be a new =3Ddefault_init inste=
ad of just =3Ddefault.</div><div><br></div><div>Remember that A::A() =3D de=
fault; is perfectly legal. Extending that to A::A(foo) =3D default or A::A(=
foo) : A() =3D default is a small step. The =3Ddefault basically translates=
 to &quot;ignore implicit supression if present and supply a trivial empty =
body; if all other invoked member initializations, implicit or explicit, ar=
e trivial, then this is trivial as well.&quot;</div></div></blockquote><div=
><br>But that&#39;s not what `=3D default` means. Defaulting a copy constru=
ctor does not &quot;supply a trivial empty body&quot;; it supplies a <i>rea=
l</i> function definition that may or may not be trivial depending on what =
that definition has to do.<br></div></div></blockquote><div><br></div><div>=
Well understood, and I&#39;ve not (intentionally) tried to imply anything e=
lse. :)</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">=
<div dir=3D"ltr"><div>The reason to go with a new term rather than `=3D def=
ault` is so that it can have different semantics from `=3D default`. If you=
 `=3D default` a default constructor, the default member initializers are s=
till invoked. Whereas if you `=3D default_init` it, then the DMI&#39;s are =
<i>ignored</i>.<br></div></div></blockquote><div><br></div><div>I think tha=
t&#39;s particularly dangerous.</div><div><br></div><div>It&#39;s a very mu=
ddled place between `A::A() =3D default` and `A::A() =3D default_init` havi=
ng wildly different and potentially disastrously different semantics.</div>=
<div><br></div><div>Explicit beats implicit. If I want to override a DMI, t=
he language already provides a way to do so: supply an initializer in the c=
onstructor. That&#39;s the place where I should opt in (on a member-by-memb=
er basis) which initializers to suppress.</div><div><br></div><div>A::A() :=
 x(default_init) =3D meow_whatever_allows_this_to_be_trivial_meow;</div><di=
v><br></div><div>I&#39;m not married to =3Ddefault but it seems the best ch=
oice, since it already has the desired meaning and semantics, only it&#39;s=
 just not allowed outside of a handful of limited places. This is similar t=
o the comparison operations being discussed that allow them to be =3Ddefaul=
t even though the generated body will be something specific to the function=
 being defaulted.</div><div><br></div><div>In this case, =3Ddefault on a co=
nstructor - other than the copy or move constructors - would just mean &quo=
t;an empty body that may be trivial iff the member and base initializers ar=
e trivial.&quot; Which is at its core the exact meaning you get today with =
=3Ddefault on the default constructor, so it&#39;s consistent and already w=
ell-understood and doesn&#39;t require new concepts or keywords or rules to=
 be taught - it&#39;s just a generalization of =3Ddefault. :)</div><div>=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div=
><br>Furthermore, if you `=3D default` a default constructor, but one of th=
e subobjects cannot be default constructed, then the default constructor is=
 internally `=3D delete`d. That&#39;s not the behavior we want when using `=
=3D default_init`; if the type cannot be default initialized, then the code=
 should be ill-formed.<br></div></div></blockquote><div><br></div><div>I&#3=
9;m missing the distinction here, I think.</div><div>=C2=A0</div><blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br>There&#39;s a =
difference between these two classes:<br><br><div style=3D"background-color=
:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-w=
idth:1px"><code><div><span style=3D"color:#008">class</span><span style=3D"=
color:#000"> A<br></span><span style=3D"color:#660">{</span><span style=3D"=
color:#000"><br></span><span style=3D"color:#008">public</span><span style=
=3D"color:#660">:</span><span style=3D"color:#000"><br>=C2=A0 A</span><span=
 style=3D"color:#660">()</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#660">=3D</span><span style=3D"color:#000"> default_init</span>=
<span style=3D"color:#660">;</span><span style=3D"color:#000"><br><br></spa=
n><span style=3D"color:#008">private</span><span style=3D"color:#660">:</sp=
an><span style=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">=
int</span><span style=3D"color:#000"> i </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> </span><span style=3D"color:#066">20<=
/span><span style=3D"color:#660">;</span><span style=3D"color:#000"><br></s=
pan><span style=3D"color:#660">};</span><span style=3D"color:#000"><br><br>=
</span><span style=3D"color:#008">class</span><span style=3D"color:#000"> B=
<br></span><span style=3D"color:#660">{</span><span style=3D"color:#000"><b=
r></span><span style=3D"color:#008">public</span><span style=3D"color:#660"=
>:</span><span style=3D"color:#000"><br>=C2=A0 B</span><span style=3D"color=
:#660">()</span><span style=3D"color:#000"> </span><span style=3D"color:#66=
0">=3D</span><span style=3D"color:#000"> </span><span style=3D"color:#008">=
default</span><span style=3D"color:#660">;</span><span style=3D"color:#000"=
><br><br></span><span style=3D"color:#008">private</span><span style=3D"col=
or:#660">:</span><span style=3D"color:#000"><br>=C2=A0 </span><span style=
=3D"color:#008">int</span><span style=3D"color:#000"> i </span><span style=
=3D"color:#660">=3D</span><span style=3D"color:#000"> </span><span style=3D=
"color:#066">20</span><span style=3D"color:#660">;</span><span style=3D"col=
or:#000"><br></span><span style=3D"color:#660">};</span></div></code></div>=
<br>`B` will always initialize its member, while `A()` will leave it uninit=
ialized (though this will be true even in value initialization, so it&#39;s=
 probably not a good idea to slap `=3D default_init` on a default construct=
or). This is asking for a different kind of code generation. So you should =
need to use a new syntax for that.<br></div></div></blockquote><div><br></d=
iv><div>A could also just be given using my suggestion with something like:=
</div><div><br></div><blockquote style=3D"margin: 0 0 0 40px; border: none;=
 padding: 0px;"><div><span style=3D"font-family: monospace; background-colo=
r: rgb(250, 250, 250); color: rgb(0, 0, 136);">class</span><span style=3D"f=
ont-family: monospace; background-color: rgb(250, 250, 250); color: rgb(0, =
0, 0);">=C2=A0A<br></span></div><div><span style=3D"font-family: monospace;=
 background-color: rgb(250, 250, 250); color: rgb(102, 102, 0);">{</span></=
div><div><span style=3D"font-family: monospace; background-color: rgb(250, =
250, 250); color: rgb(0, 0, 136);">public</span><span style=3D"font-family:=
 monospace; background-color: rgb(250, 250, 250); color: rgb(102, 102, 0);"=
>:</span></div><div><span style=3D"font-family: monospace; background-color=
: rgb(250, 250, 250); color: rgb(0, 0, 0);">=C2=A0 A</span><span style=3D"f=
ont-family: monospace; background-color: rgb(250, 250, 250); color: rgb(102=
, 102, 0);">()</span><span style=3D"font-family: monospace; background-colo=
r: rgb(250, 250, 250); color: rgb(0, 0, 0);">=C2=A0: i{std::default_init}=
=C2=A0</span><span style=3D"font-family: monospace; background-color: rgb(2=
50, 250, 250); color: rgb(102, 102, 0);">=3D</span><span style=3D"font-fami=
ly: monospace; background-color: rgb(250, 250, 250); color: rgb(0, 0, 0);">=
=C2=A0default</span><span style=3D"font-family: monospace; background-color=
: rgb(250, 250, 250); color: rgb(102, 102, 0);">; // A() has an empty body =
and only trivial member initialization, so it&#39;s trivial</span></div><di=
v><span style=3D"font-family: monospace; background-color: rgb(250, 250, 25=
0); color: rgb(0, 0, 0);"><br></span></div><div><span style=3D"font-family:=
 monospace; background-color: rgb(250, 250, 250); color: rgb(0, 0, 136);">p=
rivate</span><span style=3D"font-family: monospace; background-color: rgb(2=
50, 250, 250); color: rgb(102, 102, 0);">:</span></div><div><span style=3D"=
font-family: monospace; background-color: rgb(250, 250, 250); color: rgb(0,=
 0, 0);">=C2=A0=C2=A0</span><span style=3D"font-family: monospace; backgrou=
nd-color: rgb(250, 250, 250); color: rgb(0, 0, 136);">int</span><span style=
=3D"font-family: monospace; background-color: rgb(250, 250, 250); color: rg=
b(0, 0, 0);">=C2=A0i=C2=A0</span><span style=3D"font-family: monospace; bac=
kground-color: rgb(250, 250, 250); color: rgb(102, 102, 0);">=3D</span><spa=
n style=3D"font-family: monospace; background-color: rgb(250, 250, 250); co=
lor: rgb(0, 0, 0);">=C2=A0</span><span style=3D"font-family: monospace; bac=
kground-color: rgb(250, 250, 250); color: rgb(0, 102, 102);">20</span><span=
 style=3D"font-family: monospace; background-color: rgb(250, 250, 250); col=
or: rgb(102, 102, 0);">; // essentially pointless NSDMI for this type</span=
></div><div><span style=3D"font-family: monospace; background-color: rgb(25=
0, 250, 250); color: rgb(102, 102, 0);">};</span></div></blockquote><div>=
=C2=A0</div><div>The default constructor for A would then override its i me=
mber initializer to be uninitialized and allow the body to be generated by =
the compiler and hence detected in this case as being trivial.</div><div><b=
r></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>=
<br>Now, perhaps `=3D default_init` is the wrong term. What you&#39;re real=
ly creating is an <i>uninitializing</i> constructor: a constructor that in =
theory performs no initialization. The only initialization it may perform i=
s calling default constructors for subobjects that aren&#39;t trivially def=
ault constructible. But it would not invoke default member initializers.<br=
><br>I think. I&#39;m still fairly up in the air about what the semantics o=
f these things should be (though they do need to be <i>able</i> to be diffe=
rent from `=3D default`). Maybe they should fail to compile if any subobjec=
ts are not trivially default constructible. Maybe it should be `=3D trivial=
`.<br></div></div></blockquote><div><br></div><div>I&#39;m leaning towards =
=3Ddefault because the idea isn&#39;t to be _specifically for trivial objec=
ts_. Again, I can&#39;t stress enough that I want avoid one-off features an=
d aim for generality.</div><div><br></div><div>My suggestion is to be a gen=
eral facility that is a building block for your default_init and for uninit=
ialized construction and for making certain meta-programming Just Work(tm) =
as trivial when and if the various SFINAE, Concepts, and specializations ma=
y require it. Consider your example previously, but replace the integer mem=
ber with something &quot;trickier&quot;:</div><div><br></div><div class=3D"=
prettyprint" style=3D"background-color: rgb(250, 250, 250); border-color: r=
gb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: break=
-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">template</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">class</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> T</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> <br></span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">class</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> A </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">public</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 A</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">C</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">T</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> i</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> m</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">i</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">foo</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">())</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">default</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;"=
 class=3D"styled-by-prettify">// this may or may not be trivial, dependent =
on B(decltype(C&lt;T&gt;::foo()))</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 </span><span style=3D"color: #800;" class=3D"styled-by-prettify">// =
being trivial, but the body {} will never be trivial</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br><br><br></span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">private</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">:</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br>=C2=A0 B</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">T</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> m</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">;</span></div></code></div><div>=C2=A0</div><div>In the above type wit=
h C++ today or with just your default_init, there is no way to define A::A =
that will ever be trivial, even if the member initialize it invokes is triv=
ial (say, C&lt;T&gt;::foo() might return a B&lt;T&gt; const&amp; which invo=
kes a trivial copy constructor. That&#39;s because today, you must put a bo=
dy {} on the definition, which the compiler will never ever interpret as tr=
ivial. That&#39;s a language limitation that has absolutely nothing to do w=
ith either your or my user case and yet would be corrected with my suggesti=
on. Generality is good. :)</div><div><br></div><div><br></div><div>In my pe=
rsonal and probably unimportant opinion a very key design goal for language=
s is to aim for small reuable bits of functionality instead of large chunks=
 of purpose-built functionality. It&#39;s composable and emergent rather th=
an rigid and limited.<br><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div dir=3D"ltr"><div><br>Since you&#39;re going to have to change [d=
cl.init] anyway, it&#39;s much easier to insert the following rule between =
17.2 and 17.3:<br><br>&gt; 17.3.new: if the initializer is a single express=
ion of type `std::default_init_t`, then the object is default-initialized.<=
br><br>Your way would require inserting an <i>almost identical</i> rule, wi=
th the only difference being that the rule would only apply to non-class ty=
pes. Then you have to insert a bunch of stuff in Chapter 12 about this new =
special member function.<br><br>It&#39;s much simpler for the standard to j=
ust say that all types treat initialization from `std::default_init_t` in t=
he same way.</div></div></blockquote><div><br></div><div>That actually is a=
 nice point that does counter-balance away some of my concerns nicely. :)=
=C2=A0</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/3c0ceb25-43ac-478d-8794-6e37e4784cc7%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/3c0ceb25-43ac-478d-8794-6e37e4784cc7=
%40isocpp.org</a>.<br />

------=_Part_3306_1865747843.1482703657492--

------=_Part_3305_1083689784.1482703657491--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 25 Dec 2016 19:06:47 -0800 (PST)
Raw View
------=_Part_704_890513864.1482721607520
Content-Type: multipart/alternative;
 boundary="----=_Part_705_1267704886.1482721607522"

------=_Part_705_1267704886.1482721607522
Content-Type: text/plain; charset=UTF-8

On Sunday, December 25, 2016 at 5:07:37 PM UTC-5, Sean Middleditch wrote:
>
> On Monday, December 19, 2016 at 8:45:11 AM UTC-8, Nicol Bolas wrote:
>>
>> On Monday, December 19, 2016 at 1:43:29 AM UTC-5, Sean Middleditch wrote:
>>>
>>> On Saturday, December 17, 2016 at 8:26:26 AM UTC-8, Nicol Bolas wrote:
>>>>
>>>> Which makes me think: perhaps instead of making default_init_t
>>>>> *completely* magic we could instead loosen the rules for constructor to
>>>>> allow any constructor to have =default instead of a body. The compiler can
>>>>> then easily determine if the constructor is trivial or not via the existing
>>>>> rules. All types could then have a "magic" constructor
>>>>> foo::foo(std::default_init_t) : foo() = default; implicitly generated if
>>>>> the default constructor isn't deleted. This also makes the overload
>>>>> question I posed much simpler to answer since the answer becomes implied. I
>>>>> think the generality is a better design in (ahem 2) general, but in this
>>>>> case it also means existing code (like mine) using a similar type/trick can
>>>>> just replace their empty constructor bodies with =default to become
>>>>> trivial, just like we did with default constructors in C++11.
>>>>>
>>>>
>>>> I *really* don't like this idea.
>>>>
>>>> The whole point of this feature is to permit a user to default
>>>> initialize any type `T` by doing `T t = default_init;`. Therefore, that
>>>> statement must always be *equivalent* to `T t;`.
>>>>
>>>
>>> Here we'll disagree then. :)
>>>
>>
>> But... that's the problem domain I outlined: I have some type T, which is
>> being initialized through some forwarded interface, and I want to invoke
>> default initialization on it. That's not the problem that your method
>> solves. It never actually invokes the rules of default initialization; you
>> merely get to call a constructor that maybe doesn't initialize the object's
>> data.
>>
>
> I get it's not the same. What I'm getting at is that you can have two
> "small" features combine into multiple bigger features, instead of needing
> to define two separate big features. :)
>
>
>>
>> That's not the same thing. For reasons you'll see next:
>>
>> The magic value approach sits very poorly with me. I'd prefer to minimize
>>> its impact on the language to the smallest possible degree. I believe your
>>> use case can be achieve with nothing more than introducing the
>>> automatically generated constructor _if_ there's also a way to note that
>>> forwarded constructors can inherit triviality... which my added suggestions
>>> provides (and that suggestion provides more use cases than just making your
>>> feature work, which implies that it has relatively high value so far as the
>>> difficulty-to-usefulness ratio goes).
>>>
>>
>> OK, explain how I would do this without compiler magic:
>>
>> vector<int> v;
>> v.emplace_back(std::default_init);
>>
>> This statement is going to call `allocator_traits::construct(a, p,
>> std::default_init)`. Which will eventually perform `new(p)
>> int(std::default_init)`.
>>
>> If `std::default_init_t` is a regular type, that's a compile error. The
>> only way to make this compile without compiler magic is to make
>> `std::default_init_t` implicitly convertible to a (presumably
>> default-initialized) value of any basic type. But that causes all kinds of
>> *other* problems.
>>
>> So compiler magic is going to have to happen, one way or another.
>>
>
> Certainly, which I acknowledged - the "minimal" magic would be to provide
> a std::default_init_t type for all types (built-in or otherwise), but
> literally no other special rules regarding the constructor signature. This
> isn't even a huge deal of magic since we already have standard support for
> compiler-generated constructors (default, copy, and move, specifically).
> With the =default feature, the definition of this generated
> std::default_init_t is also pretty much solved without needing to add
> additional language for what default_init_t does into the standard's
> grammar definition.
>
> e.g., less magic.
>
>
>>
>>
>>> If you use this magic constructor method, users can now *override*
>>>> `default_init_t` initialization. That completely destroys the whole purpose
>>>> of the feature. `T t`; will always follow [dcl.init]/7, while `T t =
>>>> default_init;` is just like any other constructor call.
>>>>
>>>
>>> Unless of course that's what the author of the library wanted. Why
>>> shouldn't an expert library author be able to override the constructor?
>>> There are valid use cases to be able to override just about everything
>>> else, which is allowed. I don't think it's terribly important to be able to
>>> override it, but I'm not sure what you're really buying in real-world
>>> utility by adding special cases here.
>>>
>>
>> The utility is that the code does what it says. It performs default
>> initialization, as that is defined in the standard. Not "whatever form of
>> initialization the user has substituted for `default_init`.
>>
>
> Fair. I'm not convinced that's all that important given all the other
> overload magic tricks users can do, though.
>
> If you are sure that there must be a non-overloadable way of specifying
> default values, then my bike-shedding preference would be to avoid a magic
> library type for the purpose
>

If there's no type, then you cannot perform default initialization through
`emplace`-like functions, nor can you have `vector` default-initialize its
members. The only thing left in the proposal at that point is just a way to
default initialize objects we directly initialize. Which we *already have*.
What we lack is a way to *indirectly* invoke default initialization.

Without the type, the proposal is just dead weight.

That being said, since `default` is a keyword already, and one that
surprisingly doesn't get used very often, it might not be unreasonable to
make it resolve to a prvalue expression of `std::default_init_t` type. Much
like `nullptr`. But the default initialization still has to key off of the
expression's type, not merely the use of the keyword.

, e.g. maybe to just allow `default` as an expression and to make the
> language have specific rules that the constructor A(default) is equivalent
> to A(). It would make your proposal feel more like nullptr's place in the
> language and less like std::initializer_list (and yeah, I'm salty still
> about the later and consider it a language wart, but that's me).
>
> That also makes it a lot more clear and non-magic about why it can't be
> overloaded: it's much clearer that a declaration A::A(default) is just a
> synonym for A::A() the same way that f(void) is a synonym for f(). I like
> consistent, clear, and obvious grammar. :)
>
>
>> I get what you're wanting. You want `T t` to call a default constructor,
>> while making `T t(something)` perform the equivalent of actual "default
>> initialization".
>>
>
>>>> I would say that the way to handle this is to permit a user to define a
>>>> constructor which performs default initialization of the object's members.
>>>> Like this:
>>>>
>>>> struct A
>>>> {
>>>>   A() /*non-trivial default construction*/
>>>>   A(uninitialize_t) = default_init;
>>>> };
>>>>
>>>> The code generated for that constructor will default initialize its
>>>> subobjects, overriding all default member initializers and such. If one of
>>>> the subobjects is not trivially default constructible, then this function
>>>> will not be a trivial constructor. If one of the subobjects cannot undergo
>>>> default initialization (deleted default constructor, a reference, etc),
>>>> this definition will be il-formed.
>>>>
>>>
>>> Yeah, that too, though I see no reason why it needs to be a new
>>> =default_init instead of just =default.
>>>
>>> Remember that A::A() = default; is perfectly legal. Extending that to
>>> A::A(foo) = default or A::A(foo) : A() = default is a small step. The
>>> =default basically translates to "ignore implicit supression if present and
>>> supply a trivial empty body; if all other invoked member initializations,
>>> implicit or explicit, are trivial, then this is trivial as well."
>>>
>>
>> But that's not what `= default` means. Defaulting a copy constructor does
>> not "supply a trivial empty body"; it supplies a *real* function
>> definition that may or may not be trivial depending on what that definition
>> has to do.
>>
>
> Well understood, and I've not (intentionally) tried to imply anything
> else. :)
>
>
>> The reason to go with a new term rather than `= default` is so that it
>> can have different semantics from `= default`. If you `= default` a default
>> constructor, the default member initializers are still invoked. Whereas if
>> you `= default_init` it, then the DMI's are *ignored*.
>>
>
> I think that's particularly dangerous.
>
> It's a very muddled place between `A::A() = default` and `A::A() =
> default_init` having wildly different and potentially disastrously
> different semantics.
>
> Explicit beats implicit. If I want to override a DMI, the language already
> provides a way to do so: supply an initializer in the constructor. That's
> the place where I should opt in (on a member-by-member basis) which
> initializers to suppress.
>
> A::A() : x(default_init) = meow_whatever_allows_this_to_be_trivial_meow;
>

Here's the problem I have with this. The current rules state the following:

1: Member initialization lists are part of a constructor's definition.
That's why function-level try/catch blocks can catch exceptions thrown by
subobject initialization.
2: `= default` is the totality of a constructor's definition.
3: A constructor is user-provided if the user has given it a definition
that isn't defaulted.
4: A constructor which is user-provided cannot be trivial.

In order for this syntax to have the effect you want, *at least one* of
these rules must change.

Rules #1&2 are built into C++'s *grammar*. Take a look at
[dcl.fct.def.general]/1. `function-definition` includes `function-body`.
And `function-body` *either* has `ctor-initializer` followed by
`compound-statement`, or it has `= default/delete` (or a function-try/catch
block). Grammatically, it is impossible to have both `= default` and member
initializers.

Obviously grammar can be changed; you could stick an optional
`ctor-initializer` in front of `= default`. But that's part of my point;
your way requires a significant restructuring of all of these rules. It
increases complexity for both the standard and the user. It now has to say
what it means to `= default` and provide initializers. What does that mean
for copy/move constructors, for example?

And most important of all, what are the rules for when a constructor is
"user-provided"? Right now, the rules are fairly simple: it's user-provided
if the type has DMIs, virtuals, or if the constructor's definition is
anything other than `= default/delete`. Now, you have to add rules saying
that user-provided constructors can have DMI'd members, but all of those
members must be explicitly default initialized for that constructor with
`default_init`. And it has to use that *exact* expression:
`std::default_init` itself. It cannot use some expression which evaluates
to an object of type `std::default_init_t` (for reasons I'll explain below).

My way simply adds `= default_init` to `function-body` and to the list of
the user-provided rules.

Now to be fair, it does add some other things here and there. Namely, that
an object which has a constructor that is an uninitializing constructor can
undergo vacuous initialization ([basic.life]/1). Also, your type can be
uninitializable if its subobjects can be unitialized, whether through a
trivial default constructor or a (public?) uninitializing constructor.

That is, consider this:

struct Inner
{
  int j = 5;

  Inner() = default;
  Inner(test) = default_init; //I really would prefer `uninit`, which could
be a special identifier.
};

struct Outer
{
  Inner i;

  Outer() = default;  //Also, could use `default_init` to guarantee
triviality.
};

`Inner` is not trivially default constructible, by design. But it does have
an accessible uninitializing constructor. And therefore, the type is
"uninitializable". As such, `Outer` is allowed to be trivially default
constructible. Logically, it initializes `Outer::i` by calling the
uninitializing constructor of `Inner`. Of course in actuality it will do
nothing.

Basically, by having an accessible uninitializing constructor, you're
saying that it's OK for this type to be uninitialized. So you don't care if
the constructor is called, and you have no way to test if it's called since
the compiler "writes" the definition for it.

Of course, that last bit is not entirely true; the construction and
destruction of the uninitializing constructor's parameter(s) could provoke
side effects. But I consider eliding those to be OK; if you make a public
uninitializing constructor, then you are consenting to it being used in
this way.

I'm not married to =default but it seems the best choice, since it already
> has the desired meaning and semantics, only it's just not allowed outside
> of a handful of limited places. This is similar to the comparison
> operations being discussed that allow them to be =default even though the
> generated body will be something specific to the function being defaulted.
>
> In this case, =default on a constructor - other than the copy or move
> constructors - would just mean "an empty body that may be trivial iff the
> member and base initializers are trivial." Which is at its core the exact
> meaning you get today with =default on the default constructor, so it's
> consistent and already well-understood and doesn't require new concepts or
> keywords or rules to be taught - it's just a generalization of =default. :)
>

But that's not what `= default` means.

From the standard, the purpose of `= default` is to make the compiler
generate the code and behavior that it would have generated if not for the
presence of other user-provided special member functions. It's not about
having "an empty body," it's about making sure a copy constructor still
gets generated, even though you've provided a move constructor (which would
have prevented it from being generated).

Furthermore, if you `= default` a default constructor, but one of the
>> subobjects cannot be default constructed, then the default constructor is
>> internally `= delete`d. That's not the behavior we want when using `=
>> default_init`; if the type cannot be default initialized, then the code
>> should be ill-formed.
>>
>
> I'm missing the distinction here, I think.
>

OK, I said that wrong.

Let's say you have a type `A` which can be default constructed, but its
members always initialized to specific values. That is, it has a
user-provided default constructor.

Now, let's say you have this:

struct B
{
  A a;
  B() a(std::default_init) = default; //Your way
  B() = default_init; //My way.
};

The result of your way is... nothing. `B::a` will still be initialized,
because `A` can be default initialized. What `A` cannot be is
*uninitialized*. Therefore, your default constructor will be non-trivial.
Indeed, you didn't even need `a(std::default_init)`, since that would
happen anyway.

The result of my way is a *compile error*. You asked `B` to declare a
trivial constructor that would leave the object in an uninitialized state.
But one of its subobjects cannot be left in such a state. Therefore, you
have contradicted yourself, so compilation must cease.

`= default` is not a request for a trivial default constructor; it isn't
even a request for *any* default constructor, since circumstances can leave
it `delete`d. `= default_init` is a request for a trivial, uninitializing
constructor; if it cannot be trivial, then you asked for something the
compiler can't give you, so you get an error.

So if you see a type with a `= default_init` constructor, you *know* the
type can be uninitialized.

There's a difference between these two classes:
>>
>> class A
>> {
>> public:
>>   A() = default_init;
>>
>> private:
>>   int i = 20;
>> };
>>
>> class B
>> {
>> public:
>>   B() = default;
>>
>> private:
>>   int i = 20;
>> };
>>
>> `B` will always initialize its member, while `A()` will leave it
>> uninitialized (though this will be true even in value initialization, so
>> it's probably not a good idea to slap `= default_init` on a default
>> constructor). This is asking for a different kind of code generation. So
>> you should need to use a new syntax for that.
>>
>
> A could also just be given using my suggestion with something like:
>
> class A
> {
> public:
>   A() : i{std::default_init} = default; // A() has an empty body and only
> trivial member initialization, so it's trivial
>
> private:
>   int i = 20; // essentially pointless NSDMI for this type
> };
>
>
> The default constructor for A would then override its i member initializer
> to be uninitialized and allow the body to be generated by the compiler and
> hence detected in this case as being trivial.
>

And if I add a second member variable with a DMI, then I have to
`default_init` that too. And if I add a third, I have to `default_init`
that too. Otherwise, I change the semantics of the type. *Silently*. Or if
not silently, then likely far from the place where I made the mistake.

If my goal is to create an uninitializing constructor, I fail to see why I
should have to explicitly mark every subobject to be uninitialized, when I
can just mark the constructor itself. After all, that's what behavior I'm
requesting.

That's the problem sometimes with a generic solution; it makes life harder
on those looking for a specific solution.

Now, perhaps `= default_init` is the wrong term. What you're really
>> creating is an *uninitializing* constructor: a constructor that in
>> theory performs no initialization. The only initialization it may perform
>> is calling default constructors for subobjects that aren't trivially
>> default constructible. But it would not invoke default member initializers.
>>
>> I think. I'm still fairly up in the air about what the semantics of these
>> things should be (though they do need to be *able* to be different from
>> `= default`). Maybe they should fail to compile if any subobjects are not
>> trivially default constructible. Maybe it should be `= trivial`.
>>
>
> I'm leaning towards =default because the idea isn't to be _specifically
> for trivial objects_. Again, I can't stress enough that I want avoid
> one-off features and aim for generality.
>

> My suggestion is to be a general facility that is a building block for
> your default_init and for uninitialized construction and for making certain
> meta-programming Just Work(tm) as trivial when and if the various SFINAE,
> Concepts, and specializations may require it. Consider your example
> previously, but replace the integer member with something "trickier":
>
> template <class T>
> class A {
> public:
>   A(C<T> i) : m(i.foo()) = default; // this may or may not be trivial,
> dependent on B(decltype(C<T>::foo()))
>                                     // being trivial, but the body {}
> will never be trivial
>
>
> private:
>   B<T> m;
>
>
In the above type with C++ today or with just your default_init, there is
> no way to define A::A that will ever be trivial, even if the member
> initialize it invokes is trivial (say, C<T>::foo() might return a B<T>
> const& which invokes a trivial copy constructor. That's because today, you
> must put a body {} on the definition, which the compiler will never ever
> interpret as trivial. That's a language limitation that has absolutely
> nothing to do with either your or my user case and yet would be corrected
> with my suggestion. Generality is good. :)
>

Like with the meaning of `= default`, it seems that we are thinking about
two very different things with regard to the concept of "trivial". The
following explains the standard's view of this concept.

Trivial, when applied to default constructors, means that the type has
vacuous initialization; that changes how its lifetime works, in accord with
[basic.life]/1. A object with a trivial default constructor which undergoes
default initialization is *uninitialized*. Taken together, this means that
no code needs to be executed to default initialize the object. This is the
entire point of having trivial default constructors as a language concept.

Trivial, when applied to copy/move constructors/assignment, means that the
type is effectively memcpy-able (if all of them are trivial/deleted). This
is the minimum possible code for a type's copy/move operation that actually
copies/moves the value representation. This is the entire point of having
trivial copy/move constructors/assignment operators as a language concept.

Trivial, when applied to destructors, again affects lifetime rules. Calling
a trivial destructor doesn't even end the lifetime of the object. An object
with a trivial destructor is just a piece of memory. Such a destructor does
nothing. This is the entire point of having trivial destructors as a
language concept.

If the term "trivial" had a basic definition, then I would say it's this: a
trivial operation is one that you can either ignore or bypass with a
generic mechanism. Trivial default constructors are not necessary to be
called to initialize the object. A trivially copyable class can be
`memcpy`d instead of actually calling the copy/move. And trivially
destructible types don't need to have destructors called on them at all.

Given this definition, it makes absolutely no sense for a constructor which
calls a user-provided function to be considered "trivial". It's not a
matter of how you spell it in the syntax; the concept of a trivial
operation calling a user-specified function is a contradiction in terms.

But OK, let's expand the definition of a trivial constructor to encompass
your `A(C<T>)`. So... what does that mean we can do with this function? We
cannot initialize `A` through this constructor without calling it, since it
has side-effects that *must* happen. If that were a copy-constructor, it
would not make `memcpy` equivalent to calling the copy constructor since it
has side-effects that `memcpy` cannot replicate. And so on.

The generality you have created here accomplishes nothing. Declaring that
`A(C<T>)` is a "trivial" constructor says nothing about that constructor's
behavior. It has side-effects, so user code still must be called; as such,
it cannot be bypassed in any way. So how is `A(C<T> i) : m(i.foo()) =
default;` any different from `A(C<T> i) : m(i.foo()) {}`? What code would
be legal on the `= default` version but not on the other?

What good is the "generality" you have proposed here?

In my personal and probably unimportant opinion a very key design goal for
> languages is to aim for small reuable bits of functionality instead of
> large chunks of purpose-built functionality. It's composable and emergent
> rather than rigid and limited.
>

I don't agree with that. That sort of thinking leads to the worst aspects
of Lua: complete un-interoperability. Lua has a fantastically generic
object model with its tables, which you can use to build classes. But
because the language doesn't define classes as a first-class construct,
just the pieces needed to build them, everyone builds them *differently*.
So you can't really derive from someone else's class. And if you can, you
can't derive from two different people's classes in the same object. Not
without writing a lot of forwarding boilerplate.

But that's actually great for Lua's primary purpose: being embedded in
applications. In such an environment, you can construct the specific
functionality your Lua users need, and let it go with that. But that only
works because the people using that environment are highly dependent on the
provider of that environment. In a more open world, when you're pulling in
libraries and modules from wherever, it's a recipe for chaos.

The key questions to me for a language proposal are:

1: Is the problem the proposal says it solves important enough to be worth
solving in the language?

2: Does the proposal actually solve that problem?

3: Are there any other problems near that domain which small tweaks to the
proposal could solve?

4: Is there anything we could lose from the proposal while still solving
the problem?

5: Are there other ways to solve this problem that might be better in some
way?

6: Does the language feature mesh well with the existing language
infrastructure and features?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/168ab676-be9f-44dd-90de-cbe532cf0617%40isocpp.org.

------=_Part_705_1267704886.1482721607522
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Sunday, December 25, 2016 at 5:07:37 PM UTC-5, Sean Mid=
dleditch wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr=
">On Monday, December 19, 2016 at 8:45:11 AM UTC-8, Nicol Bolas wrote:<bloc=
kquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-lef=
t:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On Monday, December 19,=
 2016 at 1:43:29 AM UTC-5, Sean Middleditch wrote:<blockquote class=3D"gmai=
l_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pad=
ding-left:1ex"><div dir=3D"ltr">On Saturday, December 17, 2016 at 8:26:26 A=
M UTC-8, Nicol Bolas wrote:<blockquote class=3D"gmail_quote" style=3D"margi=
n:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=
=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>Whic=
h makes me think: perhaps instead of making default_init_t *completely* mag=
ic we could instead loosen the rules for constructor to allow any construct=
or to have =3Ddefault instead of a body. The compiler can then easily deter=
mine if the constructor is trivial or not via the existing rules. All types=
 could then have a &quot;magic&quot; constructor foo::foo(std::default_init=
_t) : foo() =3D default; implicitly generated if the default constructor is=
n&#39;t deleted. This also makes the overload question I posed much simpler=
 to answer since the answer becomes implied. I think the generality is a be=
tter design in (ahem 2) general, but in this case it also means existing co=
de (like mine) using a similar type/trick can just replace their empty cons=
tructor bodies with =3Ddefault to become trivial, just like we did with def=
ault constructors in C++11.<br></div></div></blockquote><div><br>I <i>reall=
y</i> don&#39;t like this idea.<br><br>The whole point of this feature is t=
o permit a user to default initialize any type `T` by doing `T t =3D defaul=
t_init;`. Therefore, that statement must always be <i>equivalent</i> to `T =
t;`.<br></div></div></blockquote><div><br></div><div>Here we&#39;ll disagre=
e then. :)</div></div></blockquote><div><br>But... that&#39;s the problem d=
omain I outlined: I have some type T, which is being initialized through so=
me forwarded interface, and I want to invoke default initialization on it. =
That&#39;s not the problem that your method solves. It never actually invok=
es the rules of default initialization; you merely get to call a constructo=
r that maybe doesn&#39;t initialize the object&#39;s data.<br></div></div><=
/blockquote><div><br></div><div>I get it&#39;s not the same. What I&#39;m g=
etting at is that you can have two &quot;small&quot; features combine into =
multiple bigger features, instead of needing to define two separate big fea=
tures. :)</div><div>=C2=A0<br></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr"><div><br>That&#39;s not the same thing. For reasons you&#=
39;ll see next:<br><br></div><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div d=
ir=3D"ltr"><div></div><div>The magic value approach sits very poorly with m=
e. I&#39;d prefer to minimize its impact on the language to the smallest po=
ssible degree. I believe your use case can be achieve with nothing more tha=
n introducing the automatically generated constructor _if_ there&#39;s also=
 a way to note that forwarded constructors can inherit triviality... which =
my added suggestions provides (and that suggestion provides more use cases =
than just making your feature work, which implies that it has relatively hi=
gh value so far as the difficulty-to-usefulness ratio goes).</div></div></b=
lockquote><div><br>OK, explain how I would do this without compiler magic:<=
br><br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187=
,187,187);border-style:solid;border-width:1px"><code><div><span style=3D"co=
lor:#000">vector</span><span style=3D"color:#080">&lt;int&gt;</span><span s=
tyle=3D"color:#000"> v</span><span style=3D"color:#660">;</span><span style=
=3D"color:#000"><br>v</span><span style=3D"color:#660">.</span><span style=
=3D"color:#000">emplace_back</span><span style=3D"color:#660">(</span><span=
 style=3D"color:#000">std</span><span style=3D"color:#660">::</span><span s=
tyle=3D"color:#000">default_<wbr>init</span><span style=3D"color:#660">);</=
span></div></code></div><br>This statement is going to call `allocator_trai=
ts::construct(<wbr>a, p, std::default_init)`. Which will eventually perform=
 `new(p) int(std::default_init)`.<br><br>If `std::default_init_t` is a regu=
lar type, that&#39;s a compile error. The only way to make this compile wit=
hout compiler magic is to make `std::default_init_t` implicitly convertible=
 to a (presumably default-initialized) value of any basic type. But that ca=
uses all kinds of <i>other</i> problems.<br><br>So compiler magic is going =
to have to happen, one way or another.<br></div></div></blockquote><div><br=
></div><div>Certainly, which I acknowledged - the &quot;minimal&quot; magic=
 would be to provide a std::default_init_t type for all types (built-in or =
otherwise), but literally no other special rules regarding the constructor =
signature. This isn&#39;t even a huge deal of magic since we already have s=
tandard support for compiler-generated constructors (default, copy, and mov=
e, specifically). With the =3Ddefault feature, the definition of this gener=
ated std::default_init_t is also pretty much solved without needing to add =
additional language for what default_init_t does into the standard&#39;s gr=
ammar definition.</div><div><br></div><div>e.g., less magic.</div><div>=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><blockquo=
te class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>If you use this magic =
constructor method, users can now <i>override</i> `default_init_t` initiali=
zation. That completely destroys the whole purpose of the feature. `T t`; w=
ill always follow [dcl.init]/7, while `T t =3D default_init;` is just like =
any other constructor call.<br></div></div></blockquote><div><br></div><div=
>Unless of course that&#39;s what the author of the library wanted. Why sho=
uldn&#39;t an expert library author be able to override the constructor? Th=
ere are valid use cases to be able to override just about everything else, =
which is allowed. I don&#39;t think it&#39;s terribly important to be able =
to override it, but I&#39;m not sure what you&#39;re really buying in real-=
world utility by adding special cases here.</div></div></blockquote><div><b=
r>The utility is that the code does what it says. It performs default initi=
alization, as that is defined in the standard. Not &quot;whatever form of i=
nitialization the user has substituted for `default_init`.<br></div></div><=
/blockquote><div><br></div><div>Fair. I&#39;m not convinced that&#39;s all =
that important given all the other overload magic tricks users can do, thou=
gh.</div><div><br></div><div>If you are sure that there must be a non-overl=
oadable way of specifying default values, then my bike-shedding preference =
would be to avoid a magic library type for the purpose</div></div></blockqu=
ote><div><br>If there&#39;s no type, then you cannot perform default initia=
lization through `emplace`-like functions, nor can you have `vector` defaul=
t-initialize its members. The only thing left in the proposal at that point=
 is just a way to default initialize objects we directly initialize. Which =
we <i>already have</i>. What we lack is a way to <i>indirectly</i> invoke d=
efault initialization.<br><br>Without the type, the proposal is just dead w=
eight.<br><br>That being said, since `default` is a keyword already, and on=
e that surprisingly doesn&#39;t get used very often, it might not be unreas=
onable to make it resolve to a prvalue expression of `std::default_init_t` =
type. Much like `nullptr`. But the default initialization still has to key =
off of the expression&#39;s type, not merely the use of the keyword.<br><br=
></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>,=
 e.g. maybe to just allow `default` as an expression and to make the langua=
ge have specific rules that the constructor A(default) is equivalent to A()=
.. It would make your proposal feel more like nullptr&#39;s place in the lan=
guage and less like std::initializer_list (and yeah, I&#39;m salty still ab=
out the later and consider it a language wart, but that&#39;s me).<br></div=
><div><br></div><div>That also makes it a lot more clear and non-magic abou=
t why it can&#39;t be overloaded: it&#39;s much clearer that a declaration =
A::A(default) is just a synonym for A::A() the same way that f(void) is a s=
ynonym for f(). I like consistent, clear, and obvious grammar. :)</div><div=
>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-lef=
t:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>=
I get what you&#39;re wanting. You want `T t` to call a default constructor=
, while making `T t(something)` perform the equivalent of actual &quot;defa=
ult initialization&quot;.<br></div></div></blockquote><blockquote class=3D"=
gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid=
;padding-left:1ex"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin:0;margi=
n-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">=
<div><br>I would say that the way to handle this is to permit a user to def=
ine a constructor which performs default initialization of the object&#39;s=
 members. Like this:<br><br><div style=3D"background-color:rgb(250,250,250)=
;border-color:rgb(187,187,187);border-style:solid;border-width:1px"><code><=
div><span style=3D"color:#008">struct</span><span style=3D"color:#000"> A<b=
r></span><span style=3D"color:#660">{</span><span style=3D"color:#000"><br>=
=C2=A0 A</span><span style=3D"color:#660">()</span><span style=3D"color:#00=
0"> </span><span style=3D"color:#800">/*non-trivial default construction*/<=
/span><span style=3D"color:#000"><br>=C2=A0 A</span><span style=3D"color:#6=
60">(</span><span style=3D"color:#000">uninitialize_t</span><span style=3D"=
color:#660">)</span><span style=3D"color:#000"> </span><span style=3D"color=
:#660">=3D</span><span style=3D"color:#000"> default_init</span><span style=
=3D"color:#660">;</span><span style=3D"color:#000"><br></span><span style=
=3D"color:#660">};</span></div></code></div><br>The code generated for that=
 constructor will default initialize its subobjects, overriding all default=
 member initializers and such. If one of the subobjects is not trivially de=
fault constructible, then this function will not be a trivial constructor. =
If one of the subobjects cannot undergo default initialization (deleted def=
ault constructor, a reference, etc), this definition will be il-formed.<br>=
</div></div></blockquote><div><br></div><div>Yeah, that too, though I see n=
o reason why it needs to be a new =3Ddefault_init instead of just =3Ddefaul=
t.</div><div><br></div><div>Remember that A::A() =3D default; is perfectly =
legal. Extending that to A::A(foo) =3D default or A::A(foo) : A() =3D defau=
lt is a small step. The =3Ddefault basically translates to &quot;ignore imp=
licit supression if present and supply a trivial empty body; if all other i=
nvoked member initializations, implicit or explicit, are trivial, then this=
 is trivial as well.&quot;</div></div></blockquote><div><br>But that&#39;s =
not what `=3D default` means. Defaulting a copy constructor does not &quot;=
supply a trivial empty body&quot;; it supplies a <i>real</i> function defin=
ition that may or may not be trivial depending on what that definition has =
to do.<br></div></div></blockquote><div><br></div><div>Well understood, and=
 I&#39;ve not (intentionally) tried to imply anything else. :)</div><div>=
=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left=
:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>T=
he reason to go with a new term rather than `=3D default` is so that it can=
 have different semantics from `=3D default`. If you `=3D default` a defaul=
t constructor, the default member initializers are still invoked. Whereas i=
f you `=3D default_init` it, then the DMI&#39;s are <i>ignored</i>.<br></di=
v></div></blockquote><div><br></div><div>I think that&#39;s particularly da=
ngerous.</div><div><br></div><div>It&#39;s a very muddled place between `A:=
:A() =3D default` and `A::A() =3D default_init` having wildly different and=
 potentially disastrously different semantics.</div><div><br></div><div>Exp=
licit beats implicit. If I want to override a DMI, the language already pro=
vides a way to do so: supply an initializer in the constructor. That&#39;s =
the place where I should opt in (on a member-by-member basis) which initial=
izers to suppress.</div><div><br></div><div>A::A() : x(default_init) =3D me=
ow_whatever_allows_this_to_<wbr>be_trivial_meow;</div></div></blockquote><d=
iv><br>Here&#39;s the problem I have with this. The current rules state the=
 following:<br><br>1: Member initialization lists are part of a constructor=
&#39;s definition. That&#39;s why function-level try/catch blocks can catch=
 exceptions thrown by subobject initialization.<br>2: `=3D default` is the =
totality of a constructor&#39;s definition.<br>3: A constructor is user-pro=
vided if the user has given it a definition that isn&#39;t defaulted.<br>4:=
 A constructor which is user-provided cannot be trivial.<br><br>In order fo=
r this syntax to have the effect you want, <i>at least one</i> of these rul=
es must change.<br><br>Rules #1&amp;2 are built into C++&#39;s <i>grammar</=
i>. Take a look at [dcl.fct.def.general]/1. `function-definition` includes =
`function-body`. And `function-body` <i>either</i> has `ctor-initializer` f=
ollowed by `compound-statement`, or it has `=3D default/delete` (or a funct=
ion-try/catch block). Grammatically, it is impossible to have both `=3D def=
ault` and member initializers.<br><br>Obviously grammar can be changed; you=
 could stick an optional `ctor-initializer` in front of `=3D default`. But =
that&#39;s part of my point; your way requires a significant restructuring =
of all of these rules. It increases complexity for both the standard and th=
e user. It now has to say what it means to `=3D default` and provide initia=
lizers. What does that mean for copy/move constructors, for example?<br><br=
>And most important of all, what are the rules for when a constructor is &q=
uot;user-provided&quot;? Right now, the rules are fairly simple: it&#39;s u=
ser-provided if the type has DMIs, virtuals, or if the constructor&#39;s de=
finition is anything other than `=3D default/delete`. Now, you have to add =
rules saying that user-provided constructors can have DMI&#39;d members, bu=
t all of those members must be explicitly default initialized for that cons=
tructor with `default_init`. And it has to use that <i>exact</i> expression=
: `std::default_init` itself. It cannot use some expression which evaluates=
 to an object of type `std::default_init_t` (for reasons I&#39;ll explain b=
elow).<br><br>My way simply adds `=3D default_init` to `function-body` and =
to the list of the user-provided rules.<br><br>Now to be fair, it does add =
some other things here and there. Namely, that an object which has a constr=
uctor that is an uninitializing constructor can undergo vacuous initializat=
ion ([basic.life]/1). Also, your type can be uninitializable if its subobje=
cts can be unitialized, whether through a trivial default constructor or a =
(public?) uninitializing constructor.<br><br>That is, consider this:<br><br=
><div style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187,=
 187, 187); border-style: solid; border-width: 1px; overflow-wrap: break-wo=
rd;" class=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subpre=
ttyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">struct<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #606;" class=3D"styled-by-prettify">Inner</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> j </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-pr=
ettify">5</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br>=
=C2=A0 </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Inn=
er</span><span style=3D"color: #660;" class=3D"styled-by-prettify">()</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">default</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"color: #606;" clas=
s=3D"styled-by-prettify">Inner</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify">test</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> default_init</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #800;" class=3D"styled-by-prettify">//I really would prefer `uninit`, w=
hich could be a special identifier.</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br><br></span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Oute=
r</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span =
style=3D"color: #606;" class=3D"styled-by-prettify">Inner</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> i</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"><br><br>=C2=A0 </span><span style=3D"color: #=
606;" class=3D"styled-by-prettify">Outer</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">d=
efault</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> =C2=A0</span=
><span style=3D"color: #800;" class=3D"styled-by-prettify">//Also, could us=
e `default_init` to guarantee triviality.</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">};</span></div></code></div><br>`Inner` is not tri=
vially default constructible, by design. But it does have an accessible uni=
nitializing constructor. And therefore, the type is &quot;uninitializable&q=
uot;. As such, `Outer` is allowed to be trivially default constructible. Lo=
gically, it initializes `Outer::i` by calling the uninitializing constructo=
r of `Inner`. Of course in actuality it will do nothing.<br><br>Basically, =
by having an accessible uninitializing constructor, you&#39;re saying that =
it&#39;s OK for this type to be uninitialized. So you don&#39;t care if the=
 constructor is called, and you have no way to test if it&#39;s called sinc=
e the compiler &quot;writes&quot; the definition for it.<br><br>Of course, =
that last bit is not entirely true; the construction and destruction of the=
 uninitializing constructor&#39;s parameter(s) could provoke side effects. =
But I consider eliding those to be OK; if you make a public uninitializing =
constructor, then you are consenting to it being used in this way.<br><br><=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></d=
iv><div>I&#39;m not married to =3Ddefault but it seems the best choice, sin=
ce it already has the desired meaning and semantics, only it&#39;s just not=
 allowed outside of a handful of limited places. This is similar to the com=
parison operations being discussed that allow them to be =3Ddefault even th=
ough the generated body will be something specific to the function being de=
faulted.</div><div><br></div><div>In this case, =3Ddefault on a constructor=
 - other than the copy or move constructors - would just mean &quot;an empt=
y body that may be trivial iff the member and base initializers are trivial=
..&quot; Which is at its core the exact meaning you get today with =3Ddefaul=
t on the default constructor, so it&#39;s consistent and already well-under=
stood and doesn&#39;t require new concepts or keywords or rules to be taugh=
t - it&#39;s just a generalization of =3Ddefault. :)</div></div></blockquot=
e><div><br>But that&#39;s not what `=3D default` means.<br><br>From the sta=
ndard, the purpose of `=3D default` is to make the compiler generate the co=
de and behavior that it would have generated if not for the presence of oth=
er user-provided special member functions. It&#39;s not about having &quot;=
an empty body,&quot; it&#39;s about making sure a copy constructor still ge=
ts generated, even though you&#39;ve provided a move constructor (which wou=
ld have prevented it from being generated).<br><br></div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div dir=3D"ltr"><div></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr"><div>Furthermore, if you `=3D defau=
lt` a default constructor, but one of the subobjects cannot be default cons=
tructed, then the default constructor is internally `=3D delete`d. That&#39=
;s not the behavior we want when using `=3D default_init`; if the type cann=
ot be default initialized, then the code should be ill-formed.<br></div></d=
iv></blockquote><div><br></div><div>I&#39;m missing the distinction here, I=
 think.</div></div></blockquote><div><br>OK, I said that wrong.<br><br>Let&=
#39;s say you have a type `A` which can be default constructed, but its mem=
bers always initialized to specific values. That is, it has a user-provided=
 default constructor.<br><br>Now, let&#39;s say you have this:<br><br><div =
style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, =
187); border-style: solid; border-width: 1px; overflow-wrap: break-word;" c=
lass=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"subprettypri=
nt"><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> B<br></span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 A a</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 B</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">()</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> a</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">std</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">default_init</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">default</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" cla=
ss=3D"styled-by-prettify">//Your way</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br>=C2=A0 B</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> default_init</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #800;" class=3D"styled-by-prettify">//My way.</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">};</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code></=
div><br>The result of your way is... nothing. `B::a` will still be initiali=
zed, because `A` can be default initialized. What `A` cannot be is <i>unini=
tialized</i>. Therefore, your default constructor will be non-trivial. Inde=
ed, you didn&#39;t even need `a(std::default_init)`, since that would happe=
n anyway.<br><br>The result of my way is a <i>compile error</i>. You asked =
`B` to declare a trivial constructor that would leave the object in an unin=
itialized state. But one of its subobjects cannot be left in such a state. =
Therefore, you have contradicted yourself, so compilation must cease.<br><b=
r>`=3D default` is not a request for a trivial default constructor; it isn&=
#39;t even a request for <i>any</i> default constructor, since circumstance=
s can leave it `delete`d. `=3D default_init` is a request for a trivial, un=
initializing constructor; if it cannot be trivial, then you asked for somet=
hing the compiler can&#39;t give you, so you get an error.<br><br>So if you=
 see a type with a `=3D default_init` constructor, you <i>know</i> the type=
 can be uninitialized.<br><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div dir=3D"ltr"><div></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr"><div>There&#39;s a difference between these two classes:<=
br><br><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187=
,187,187);border-style:solid;border-width:1px"><code><div><span style=3D"co=
lor:#008">class</span><span style=3D"color:#000"> A<br></span><span style=
=3D"color:#660">{</span><span style=3D"color:#000"><br></span><span style=
=3D"color:#008">public</span><span style=3D"color:#660">:</span><span style=
=3D"color:#000"><br>=C2=A0 A</span><span style=3D"color:#660">()</span><spa=
n style=3D"color:#000"> </span><span style=3D"color:#660">=3D</span><span s=
tyle=3D"color:#000"> default_init</span><span style=3D"color:#660">;</span>=
<span style=3D"color:#000"><br><br></span><span style=3D"color:#008">privat=
e</span><span style=3D"color:#660">:</span><span style=3D"color:#000"><br>=
=C2=A0 </span><span style=3D"color:#008">int</span><span style=3D"color:#00=
0"> i </span><span style=3D"color:#660">=3D</span><span style=3D"color:#000=
"> </span><span style=3D"color:#066">20</span><span style=3D"color:#660">;<=
/span><span style=3D"color:#000"><br></span><span style=3D"color:#660">};</=
span><span style=3D"color:#000"><br><br></span><span style=3D"color:#008">c=
lass</span><span style=3D"color:#000"> B<br></span><span style=3D"color:#66=
0">{</span><span style=3D"color:#000"><br></span><span style=3D"color:#008"=
>public</span><span style=3D"color:#660">:</span><span style=3D"color:#000"=
><br>=C2=A0 B</span><span style=3D"color:#660">()</span><span style=3D"colo=
r:#000"> </span><span style=3D"color:#660">=3D</span><span style=3D"color:#=
000"> </span><span style=3D"color:#008">default</span><span style=3D"color:=
#660">;</span><span style=3D"color:#000"><br><br></span><span style=3D"colo=
r:#008">private</span><span style=3D"color:#660">:</span><span style=3D"col=
or:#000"><br>=C2=A0 </span><span style=3D"color:#008">int</span><span style=
=3D"color:#000"> i </span><span style=3D"color:#660">=3D</span><span style=
=3D"color:#000"> </span><span style=3D"color:#066">20</span><span style=3D"=
color:#660">;</span><span style=3D"color:#000"><br></span><span style=3D"co=
lor:#660">};</span></div></code></div><br>`B` will always initialize its me=
mber, while `A()` will leave it uninitialized (though this will be true eve=
n in value initialization, so it&#39;s probably not a good idea to slap `=
=3D default_init` on a default constructor). This is asking for a different=
 kind of code generation. So you should need to use a new syntax for that.<=
br></div></div></blockquote><div><br></div><div>A could also just be given =
using my suggestion with something like:</div><div><br></div><blockquote st=
yle=3D"margin:0 0 0 40px;border:none;padding:0px"><div><span style=3D"font-=
family:monospace;background-color:rgb(250,250,250);color:rgb(0,0,136)">clas=
s</span><span style=3D"font-family:monospace;background-color:rgb(250,250,2=
50);color:rgb(0,0,0)">=C2=A0A<br></span></div><div><span style=3D"font-fami=
ly:monospace;background-color:rgb(250,250,250);color:rgb(102,102,0)">{</spa=
n></div><div><span style=3D"font-family:monospace;background-color:rgb(250,=
250,250);color:rgb(0,0,136)">public</span><span style=3D"font-family:monosp=
ace;background-color:rgb(250,250,250);color:rgb(102,102,0)">:</span></div><=
div><span style=3D"font-family:monospace;background-color:rgb(250,250,250);=
color:rgb(0,0,0)">=C2=A0 A</span><span style=3D"font-family:monospace;backg=
round-color:rgb(250,250,250);color:rgb(102,102,0)">()</span><span style=3D"=
font-family:monospace;background-color:rgb(250,250,250);color:rgb(0,0,0)">=
=C2=A0: i{std::default_init}=C2=A0</span><span style=3D"font-family:monospa=
ce;background-color:rgb(250,250,250);color:rgb(102,102,0)">=3D</span><span =
style=3D"font-family:monospace;background-color:rgb(250,250,250);color:rgb(=
0,0,0)">=C2=A0default</span><span style=3D"font-family:monospace;background=
-color:rgb(250,250,250);color:rgb(102,102,0)"><wbr>; // A() has an empty bo=
dy and only trivial member initialization, so it&#39;s trivial</span></div>=
<div><span style=3D"font-family:monospace;background-color:rgb(250,250,250)=
;color:rgb(0,0,0)"><br></span></div><div><span style=3D"font-family:monospa=
ce;background-color:rgb(250,250,250);color:rgb(0,0,136)">private</span><spa=
n style=3D"font-family:monospace;background-color:rgb(250,250,250);color:rg=
b(102,102,0)">:</span></div><div><span style=3D"font-family:monospace;backg=
round-color:rgb(250,250,250);color:rgb(0,0,0)">=C2=A0=C2=A0</span><span sty=
le=3D"font-family:monospace;background-color:rgb(250,250,250);color:rgb(0,0=
,136)">int</span><span style=3D"font-family:monospace;background-color:rgb(=
250,250,250);color:rgb(0,0,0)">=C2=A0i=C2=A0</span><span style=3D"font-fami=
ly:monospace;background-color:rgb(250,250,250);color:rgb(102,102,0)">=3D</s=
pan><span style=3D"font-family:monospace;background-color:rgb(250,250,250);=
color:rgb(0,0,0)">=C2=A0</span><span style=3D"font-family:monospace;backgro=
und-color:rgb(250,250,250);color:rgb(0,102,102)">20</span><span style=3D"fo=
nt-family:monospace;background-color:rgb(250,250,250);color:rgb(102,102,0)"=
>; // essentially pointless NSDMI for this type</span></div><div><span styl=
e=3D"font-family:monospace;background-color:rgb(250,250,250);color:rgb(102,=
102,0)">};</span></div></blockquote><div>=C2=A0</div><div>The default const=
ructor for A would then override its i member initializer to be uninitializ=
ed and allow the body to be generated by the compiler and hence detected in=
 this case as being trivial.</div></div></blockquote><div><br>And if I add =
a second member variable with a DMI, then I have to `default_init` that too=
.. And if I add a third, I have to `default_init` that too. Otherwise, I cha=
nge the semantics of the type. <i>Silently</i>. Or if not silently, then li=
kely far from the place where I made the mistake.<br><br>If my goal is to c=
reate an uninitializing constructor, I fail to see why I should have to exp=
licitly mark every subobject to be uninitialized, when I can just mark the =
constructor itself. After all, that&#39;s what behavior I&#39;m requesting.=
<br><br>That&#39;s the problem sometimes with a generic solution; it makes =
life harder on those looking for a specific solution.<br><br></div><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></div><blockquot=
e class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px=
 #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>Now, perhaps `=3D defau=
lt_init` is the wrong term. What you&#39;re really creating is an <i>uninit=
ializing</i> constructor: a constructor that in theory performs no initiali=
zation. The only initialization it may perform is calling default construct=
ors for subobjects that aren&#39;t trivially default constructible. But it =
would not invoke default member initializers.<br><br>I think. I&#39;m still=
 fairly up in the air about what the semantics of these things should be (t=
hough they do need to be <i>able</i> to be different from `=3D default`). M=
aybe they should fail to compile if any subobjects are not trivially defaul=
t constructible. Maybe it should be `=3D trivial`.<br></div></div></blockqu=
ote><div><br></div><div>I&#39;m leaning towards =3Ddefault because the idea=
 isn&#39;t to be _specifically for trivial objects_. Again, I can&#39;t str=
ess enough that I want avoid one-off features and aim for generality.</div>=
</div></blockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0=
px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;=
"><div><br></div></blockquote><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">=
<div dir=3D"ltr"><div></div><div>My suggestion is to be a general facility =
that is a building block for your default_init and for uninitialized constr=
uction and for making certain meta-programming Just Work(tm) as trivial whe=
n and if the various SFINAE, Concepts, and specializations may require it. =
Consider your example previously, but replace the integer member with somet=
hing &quot;trickier&quot;:</div><div><br></div><div style=3D"background-col=
or:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border=
-width:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">temp=
late</span><span style=3D"color:#000"> </span><span style=3D"color:#660">&l=
t;</span><span style=3D"color:#008">class</span><span style=3D"color:#000">=
 T</span><span style=3D"color:#660">&gt;</span><span style=3D"color:#000"> =
<br></span><span style=3D"color:#008">class</span><span style=3D"color:#000=
"> A </span><span style=3D"color:#660">{</span><span style=3D"color:#000"><=
br></span><span style=3D"color:#008">public</span><span style=3D"color:#660=
">:</span><span style=3D"color:#000"><br>=C2=A0 A</span><span style=3D"colo=
r:#660">(</span><span style=3D"color:#000">C</span><span style=3D"color:#66=
0">&lt;</span><span style=3D"color:#000">T</span><span style=3D"color:#660"=
>&gt;</span><span style=3D"color:#000"> i</span><span style=3D"color:#660">=
)</span><span style=3D"color:#000"> </span><span style=3D"color:#660">:</sp=
an><span style=3D"color:#000"> m</span><span style=3D"color:#660">(</span><=
span style=3D"color:#000">i</span><span style=3D"color:#660">.</span><span =
style=3D"color:#000">foo</span><span style=3D"color:#660">())</span><span s=
tyle=3D"color:#000"> </span><span style=3D"color:#660">=3D</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#008">default</span><span sty=
le=3D"color:#660">;</span><span style=3D"color:#000"> </span><span style=3D=
"color:#800">// this may or may not be trivial, dependent on B(decltype(C&l=
t;T&gt;::foo()))</span><span style=3D"color:#000"><br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:#800">// being =
trivial, but the body {} will never be trivial</span><span style=3D"color:#=
000"><br><br><br></span><span style=3D"color:#008">private</span><span styl=
e=3D"color:#660">:</span><span style=3D"color:#000"><br>=C2=A0 B</span><spa=
n style=3D"color:#660">&lt;</span><span style=3D"color:#000">T</span><span =
style=3D"color:#660">&gt;</span><span style=3D"color:#000"> m</span><span s=
tyle=3D"color:#660">;</span></div></code></div><div>=C2=A0</div></div></blo=
ckquote><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>=
In the above type with C++ today or with just your default_init, there is n=
o way to define A::A that will ever be trivial, even if the member initiali=
ze it invokes is trivial (say, C&lt;T&gt;::foo() might return a B&lt;T&gt; =
const&amp; which invokes a trivial copy constructor. That&#39;s because tod=
ay, you must put a body {} on the definition, which the compiler will never=
 ever interpret as trivial. That&#39;s a language limitation that has absol=
utely nothing to do with either your or my user case and yet would be corre=
cted with my suggestion. Generality is good. :)</div></div></blockquote><di=
v><br>Like with the meaning of `=3D default`, it seems that we are thinking=
 about two very different things with regard to the concept of &quot;trivia=
l&quot;. The following explains the standard&#39;s view of this concept.<br=
><br>Trivial, when applied to default constructors, means that the type has=
 vacuous initialization; that changes how its lifetime works, in accord wit=
h [basic.life]/1. A object with a trivial default constructor which undergo=
es default initialization is <i>uninitialized</i>. Taken together, this mea=
ns that no code needs to be executed to default initialize the object. This=
 is the entire point of having trivial default constructors as a language c=
oncept.<br><br>Trivial, when applied to copy/move constructors/assignment, =
means that the type is effectively memcpy-able (if all of them are trivial/=
deleted). This is the minimum possible code for a type&#39;s copy/move oper=
ation that actually copies/moves the value representation. This is the enti=
re point of having trivial copy/move constructors/assignment operators as a=
 language concept.<br><br>Trivial, when applied to destructors, again affec=
ts lifetime rules. Calling a trivial destructor doesn&#39;t even end the li=
fetime of the object. An object with a trivial destructor is just a piece o=
f memory. Such a destructor does nothing. This is the entire point of havin=
g trivial destructors as a language concept.<br><br>If the term &quot;trivi=
al&quot; had a basic definition, then I would say it&#39;s this: a trivial =
operation is one that you can either ignore or bypass with a generic mechan=
ism. Trivial default constructors are not necessary to be called to initial=
ize the object. A trivially copyable class can be `memcpy`d instead of actu=
ally calling the copy/move. And trivially destructible types don&#39;t need=
 to have destructors called on them at all.<br><br>Given this definition, i=
t makes absolutely no sense for a constructor which calls a user-provided f=
unction to be considered &quot;trivial&quot;. It&#39;s not a matter of how =
you spell it in the syntax; the concept of a trivial operation calling a us=
er-specified function is a contradiction in terms.<br><br>But OK, let&#39;s=
 expand the definition of a trivial constructor to encompass your `A(C&lt;T=
&gt;)`. So... what does that mean we can do with this function? We cannot i=
nitialize `A` through this constructor without calling it, since it has sid=
e-effects that <i>must</i> happen. If that were a copy-constructor, it woul=
d not make `memcpy` equivalent to calling the copy constructor since it has=
 side-effects that `memcpy` cannot replicate. And so on.<br><br>The general=
ity you have created here accomplishes nothing. Declaring that `A(C&lt;T&gt=
;)` is a &quot;trivial&quot; constructor says nothing about that constructo=
r&#39;s behavior. It has side-effects, so user code still must be called; a=
s such, it cannot be bypassed in any way. So how is `A(C&lt;T&gt; i) : m(i.=
foo()) =3D default;` any different from `A(C&lt;T&gt; i) : m(i.foo()) {}`? =
What code would be legal on the `=3D default` version but not on the other?=
<br><br>What good is the &quot;generality&quot; you have proposed here?<br>=
<br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><di=
v></div><div>In my personal and probably unimportant opinion a very key des=
ign goal for languages is to aim for small reuable bits of functionality in=
stead of large chunks of purpose-built functionality. It&#39;s composable a=
nd emergent rather than rigid and limited.<br></div></div></blockquote><div=
><br>I don&#39;t agree with that. That sort of thinking leads to the worst =
aspects of Lua: complete un-interoperability. Lua has a fantastically gener=
ic object model with its tables, which you can use to build classes. But be=
cause the language doesn&#39;t define classes as a first-class construct, j=
ust the pieces needed to build them, everyone builds them <i>differently</i=
>. So you can&#39;t really derive from someone else&#39;s class. And if you=
 can, you can&#39;t derive from two different people&#39;s classes in the s=
ame object. Not without writing a lot of forwarding boilerplate.<br><br>But=
 that&#39;s actually great for Lua&#39;s primary purpose: being embedded in=
 applications. In such an environment, you can construct the specific funct=
ionality your Lua users need, and let it go with that. But that only works =
because the people using that environment are highly dependent on the provi=
der of that environment. In a more open world, when you&#39;re pulling in l=
ibraries and modules from wherever, it&#39;s a recipe for chaos.<br><br>The=
 key questions to me for a language proposal are:<br><br>1: Is the problem =
the proposal says it solves important enough to be worth solving in the lan=
guage?<br><br>2: Does the proposal actually solve that problem?<br><br>3: A=
re there any other problems near that domain which small tweaks to the prop=
osal could solve?<br><br>4: Is there anything we could lose from the propos=
al while still solving the problem?<br><br>5: Are there other ways to solve=
 this problem that might be better in some way?<br><br>6: Does the language=
 feature mesh well with the existing language infrastructure and features?<=
/div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/168ab676-be9f-44dd-90de-cbe532cf0617%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/168ab676-be9f-44dd-90de-cbe532cf0617=
%40isocpp.org</a>.<br />

------=_Part_705_1267704886.1482721607522--

------=_Part_704_890513864.1482721607520--

.


Author: Sean Middleditch <sean@middleditch.us>
Date: Mon, 26 Dec 2016 00:43:08 -0800
Raw View
--001a114dae72a7d57305448bb901
Content-Type: text/plain; charset=UTF-8

You've done your homework on this one. :)

I can't entirely disagree with your 6 philosophies though those are getting
into the point of belonging a different thread so I won't try to carry that
torch here. :)

On Sun, Dec 25, 2016 at 7:06 PM, Nicol Bolas <jmckesson@gmail.com> wrote:

> On Sunday, December 25, 2016 at 5:07:37 PM UTC-5, Sean Middleditch wrote:
>>
>> On Monday, December 19, 2016 at 8:45:11 AM UTC-8, Nicol Bolas wrote:
>>>
>>> On Monday, December 19, 2016 at 1:43:29 AM UTC-5, Sean Middleditch wrote:
>>>>
>>>> On Saturday, December 17, 2016 at 8:26:26 AM UTC-8, Nicol Bolas wrote:
>>>>>
>>>>> Which makes me think: perhaps instead of making default_init_t
>>>>>> *completely* magic we could instead loosen the rules for constructor to
>>>>>> allow any constructor to have =default instead of a body. The compiler can
>>>>>> then easily determine if the constructor is trivial or not via the existing
>>>>>> rules. All types could then have a "magic" constructor
>>>>>> foo::foo(std::default_init_t) : foo() = default; implicitly generated if
>>>>>> the default constructor isn't deleted. This also makes the overload
>>>>>> question I posed much simpler to answer since the answer becomes implied. I
>>>>>> think the generality is a better design in (ahem 2) general, but in this
>>>>>> case it also means existing code (like mine) using a similar type/trick can
>>>>>> just replace their empty constructor bodies with =default to become
>>>>>> trivial, just like we did with default constructors in C++11.
>>>>>>
>>>>>
>>>>> I *really* don't like this idea.
>>>>>
>>>>> The whole point of this feature is to permit a user to default
>>>>> initialize any type `T` by doing `T t = default_init;`. Therefore, that
>>>>> statement must always be *equivalent* to `T t;`.
>>>>>
>>>>
>>>> Here we'll disagree then. :)
>>>>
>>>
>>> But... that's the problem domain I outlined: I have some type T, which
>>> is being initialized through some forwarded interface, and I want to invoke
>>> default initialization on it. That's not the problem that your method
>>> solves. It never actually invokes the rules of default initialization; you
>>> merely get to call a constructor that maybe doesn't initialize the object's
>>> data.
>>>
>>
>> I get it's not the same. What I'm getting at is that you can have two
>> "small" features combine into multiple bigger features, instead of needing
>> to define two separate big features. :)
>>
>>
>>>
>>> That's not the same thing. For reasons you'll see next:
>>>
>>> The magic value approach sits very poorly with me. I'd prefer to
>>>> minimize its impact on the language to the smallest possible degree. I
>>>> believe your use case can be achieve with nothing more than introducing the
>>>> automatically generated constructor _if_ there's also a way to note that
>>>> forwarded constructors can inherit triviality... which my added suggestions
>>>> provides (and that suggestion provides more use cases than just making your
>>>> feature work, which implies that it has relatively high value so far as the
>>>> difficulty-to-usefulness ratio goes).
>>>>
>>>
>>> OK, explain how I would do this without compiler magic:
>>>
>>> vector<int> v;
>>> v.emplace_back(std::default_init);
>>>
>>> This statement is going to call `allocator_traits::construct(a, p,
>>> std::default_init)`. Which will eventually perform `new(p)
>>> int(std::default_init)`.
>>>
>>> If `std::default_init_t` is a regular type, that's a compile error. The
>>> only way to make this compile without compiler magic is to make
>>> `std::default_init_t` implicitly convertible to a (presumably
>>> default-initialized) value of any basic type. But that causes all kinds of
>>> *other* problems.
>>>
>>> So compiler magic is going to have to happen, one way or another.
>>>
>>
>> Certainly, which I acknowledged - the "minimal" magic would be to provide
>> a std::default_init_t type for all types (built-in or otherwise), but
>> literally no other special rules regarding the constructor signature. This
>> isn't even a huge deal of magic since we already have standard support for
>> compiler-generated constructors (default, copy, and move, specifically).
>> With the =default feature, the definition of this generated
>> std::default_init_t is also pretty much solved without needing to add
>> additional language for what default_init_t does into the standard's
>> grammar definition.
>>
>> e.g., less magic.
>>
>>
>>>
>>>
>>>> If you use this magic constructor method, users can now *override*
>>>>> `default_init_t` initialization. That completely destroys the whole purpose
>>>>> of the feature. `T t`; will always follow [dcl.init]/7, while `T t =
>>>>> default_init;` is just like any other constructor call.
>>>>>
>>>>
>>>> Unless of course that's what the author of the library wanted. Why
>>>> shouldn't an expert library author be able to override the constructor?
>>>> There are valid use cases to be able to override just about everything
>>>> else, which is allowed. I don't think it's terribly important to be able to
>>>> override it, but I'm not sure what you're really buying in real-world
>>>> utility by adding special cases here.
>>>>
>>>
>>> The utility is that the code does what it says. It performs default
>>> initialization, as that is defined in the standard. Not "whatever form of
>>> initialization the user has substituted for `default_init`.
>>>
>>
>> Fair. I'm not convinced that's all that important given all the other
>> overload magic tricks users can do, though.
>>
>> If you are sure that there must be a non-overloadable way of specifying
>> default values, then my bike-shedding preference would be to avoid a magic
>> library type for the purpose
>>
>
> If there's no type, then you cannot perform default initialization through
> `emplace`-like functions, nor can you have `vector` default-initialize its
> members. The only thing left in the proposal at that point is just a way to
> default initialize objects we directly initialize. Which we *already have*.
> What we lack is a way to *indirectly* invoke default initialization.
>
> Without the type, the proposal is just dead weight.
>
> That being said, since `default` is a keyword already, and one that
> surprisingly doesn't get used very often, it might not be unreasonable to
> make it resolve to a prvalue expression of `std::default_init_t` type. Much
> like `nullptr`. But the default initialization still has to key off of the
> expression's type, not merely the use of the keyword.
>
> , e.g. maybe to just allow `default` as an expression and to make the
>> language have specific rules that the constructor A(default) is equivalent
>> to A(). It would make your proposal feel more like nullptr's place in the
>> language and less like std::initializer_list (and yeah, I'm salty still
>> about the later and consider it a language wart, but that's me).
>>
>> That also makes it a lot more clear and non-magic about why it can't be
>> overloaded: it's much clearer that a declaration A::A(default) is just a
>> synonym for A::A() the same way that f(void) is a synonym for f(). I like
>> consistent, clear, and obvious grammar. :)
>>
>>
>>> I get what you're wanting. You want `T t` to call a default constructor,
>>> while making `T t(something)` perform the equivalent of actual "default
>>> initialization".
>>>
>>
>>>>> I would say that the way to handle this is to permit a user to define
>>>>> a constructor which performs default initialization of the object's
>>>>> members. Like this:
>>>>>
>>>>> struct A
>>>>> {
>>>>>   A() /*non-trivial default construction*/
>>>>>   A(uninitialize_t) = default_init;
>>>>> };
>>>>>
>>>>> The code generated for that constructor will default initialize its
>>>>> subobjects, overriding all default member initializers and such. If one of
>>>>> the subobjects is not trivially default constructible, then this function
>>>>> will not be a trivial constructor. If one of the subobjects cannot undergo
>>>>> default initialization (deleted default constructor, a reference, etc),
>>>>> this definition will be il-formed.
>>>>>
>>>>
>>>> Yeah, that too, though I see no reason why it needs to be a new
>>>> =default_init instead of just =default.
>>>>
>>>> Remember that A::A() = default; is perfectly legal. Extending that to
>>>> A::A(foo) = default or A::A(foo) : A() = default is a small step. The
>>>> =default basically translates to "ignore implicit supression if present and
>>>> supply a trivial empty body; if all other invoked member initializations,
>>>> implicit or explicit, are trivial, then this is trivial as well."
>>>>
>>>
>>> But that's not what `= default` means. Defaulting a copy constructor
>>> does not "supply a trivial empty body"; it supplies a *real* function
>>> definition that may or may not be trivial depending on what that definition
>>> has to do.
>>>
>>
>> Well understood, and I've not (intentionally) tried to imply anything
>> else. :)
>>
>>
>>> The reason to go with a new term rather than `= default` is so that it
>>> can have different semantics from `= default`. If you `= default` a default
>>> constructor, the default member initializers are still invoked. Whereas if
>>> you `= default_init` it, then the DMI's are *ignored*.
>>>
>>
>> I think that's particularly dangerous.
>>
>> It's a very muddled place between `A::A() = default` and `A::A() =
>> default_init` having wildly different and potentially disastrously
>> different semantics.
>>
>> Explicit beats implicit. If I want to override a DMI, the language
>> already provides a way to do so: supply an initializer in the constructor.
>> That's the place where I should opt in (on a member-by-member basis) which
>> initializers to suppress.
>>
>> A::A() : x(default_init) = meow_whatever_allows_this_to_be_trivial_meow;
>>
>
> Here's the problem I have with this. The current rules state the following:
>
> 1: Member initialization lists are part of a constructor's definition.
> That's why function-level try/catch blocks can catch exceptions thrown by
> subobject initialization.
> 2: `= default` is the totality of a constructor's definition.
> 3: A constructor is user-provided if the user has given it a definition
> that isn't defaulted.
> 4: A constructor which is user-provided cannot be trivial.
>
> In order for this syntax to have the effect you want, *at least one* of
> these rules must change.
>
> Rules #1&2 are built into C++'s *grammar*. Take a look at
> [dcl.fct.def.general]/1. `function-definition` includes `function-body`.
> And `function-body` *either* has `ctor-initializer` followed by
> `compound-statement`, or it has `= default/delete` (or a function-try/catch
> block). Grammatically, it is impossible to have both `= default` and member
> initializers.
>
> Obviously grammar can be changed; you could stick an optional
> `ctor-initializer` in front of `= default`. But that's part of my point;
> your way requires a significant restructuring of all of these rules. It
> increases complexity for both the standard and the user. It now has to say
> what it means to `= default` and provide initializers. What does that mean
> for copy/move constructors, for example?
>
> And most important of all, what are the rules for when a constructor is
> "user-provided"? Right now, the rules are fairly simple: it's user-provided
> if the type has DMIs, virtuals, or if the constructor's definition is
> anything other than `= default/delete`. Now, you have to add rules saying
> that user-provided constructors can have DMI'd members, but all of those
> members must be explicitly default initialized for that constructor with
> `default_init`. And it has to use that *exact* expression:
> `std::default_init` itself. It cannot use some expression which evaluates
> to an object of type `std::default_init_t` (for reasons I'll explain below).
>
> My way simply adds `= default_init` to `function-body` and to the list of
> the user-provided rules.
>
> Now to be fair, it does add some other things here and there. Namely, that
> an object which has a constructor that is an uninitializing constructor can
> undergo vacuous initialization ([basic.life]/1). Also, your type can be
> uninitializable if its subobjects can be unitialized, whether through a
> trivial default constructor or a (public?) uninitializing constructor.
>
> That is, consider this:
>
> struct Inner
> {
>   int j = 5;
>
>   Inner() = default;
>   Inner(test) = default_init; //I really would prefer `uninit`, which
> could be a special identifier.
> };
>
> struct Outer
> {
>   Inner i;
>
>   Outer() = default;  //Also, could use `default_init` to guarantee
> triviality.
> };
>
> `Inner` is not trivially default constructible, by design. But it does
> have an accessible uninitializing constructor. And therefore, the type is
> "uninitializable". As such, `Outer` is allowed to be trivially default
> constructible. Logically, it initializes `Outer::i` by calling the
> uninitializing constructor of `Inner`. Of course in actuality it will do
> nothing.
>
> Basically, by having an accessible uninitializing constructor, you're
> saying that it's OK for this type to be uninitialized. So you don't care if
> the constructor is called, and you have no way to test if it's called since
> the compiler "writes" the definition for it.
>
> Of course, that last bit is not entirely true; the construction and
> destruction of the uninitializing constructor's parameter(s) could provoke
> side effects. But I consider eliding those to be OK; if you make a public
> uninitializing constructor, then you are consenting to it being used in
> this way.
>
> I'm not married to =default but it seems the best choice, since it already
>> has the desired meaning and semantics, only it's just not allowed outside
>> of a handful of limited places. This is similar to the comparison
>> operations being discussed that allow them to be =default even though the
>> generated body will be something specific to the function being defaulted.
>>
>> In this case, =default on a constructor - other than the copy or move
>> constructors - would just mean "an empty body that may be trivial iff the
>> member and base initializers are trivial." Which is at its core the exact
>> meaning you get today with =default on the default constructor, so it's
>> consistent and already well-understood and doesn't require new concepts or
>> keywords or rules to be taught - it's just a generalization of =default. :)
>>
>
> But that's not what `= default` means.
>
> From the standard, the purpose of `= default` is to make the compiler
> generate the code and behavior that it would have generated if not for the
> presence of other user-provided special member functions. It's not about
> having "an empty body," it's about making sure a copy constructor still
> gets generated, even though you've provided a move constructor (which would
> have prevented it from being generated).
>
> Furthermore, if you `= default` a default constructor, but one of the
>>> subobjects cannot be default constructed, then the default constructor is
>>> internally `= delete`d. That's not the behavior we want when using `=
>>> default_init`; if the type cannot be default initialized, then the code
>>> should be ill-formed.
>>>
>>
>> I'm missing the distinction here, I think.
>>
>
> OK, I said that wrong.
>
> Let's say you have a type `A` which can be default constructed, but its
> members always initialized to specific values. That is, it has a
> user-provided default constructor.
>
> Now, let's say you have this:
>
> struct B
> {
>   A a;
>   B() a(std::default_init) = default; //Your way
>   B() = default_init; //My way.
> };
>
> The result of your way is... nothing. `B::a` will still be initialized,
> because `A` can be default initialized. What `A` cannot be is
> *uninitialized*. Therefore, your default constructor will be non-trivial.
> Indeed, you didn't even need `a(std::default_init)`, since that would
> happen anyway.
>
> The result of my way is a *compile error*. You asked `B` to declare a
> trivial constructor that would leave the object in an uninitialized state.
> But one of its subobjects cannot be left in such a state. Therefore, you
> have contradicted yourself, so compilation must cease.
>
> `= default` is not a request for a trivial default constructor; it isn't
> even a request for *any* default constructor, since circumstances can
> leave it `delete`d. `= default_init` is a request for a trivial,
> uninitializing constructor; if it cannot be trivial, then you asked for
> something the compiler can't give you, so you get an error.
>
> So if you see a type with a `= default_init` constructor, you *know* the
> type can be uninitialized.
>
> There's a difference between these two classes:
>>>
>>> class A
>>> {
>>> public:
>>>   A() = default_init;
>>>
>>> private:
>>>   int i = 20;
>>> };
>>>
>>> class B
>>> {
>>> public:
>>>   B() = default;
>>>
>>> private:
>>>   int i = 20;
>>> };
>>>
>>> `B` will always initialize its member, while `A()` will leave it
>>> uninitialized (though this will be true even in value initialization, so
>>> it's probably not a good idea to slap `= default_init` on a default
>>> constructor). This is asking for a different kind of code generation. So
>>> you should need to use a new syntax for that.
>>>
>>
>> A could also just be given using my suggestion with something like:
>>
>> class A
>> {
>> public:
>>   A() : i{std::default_init} = default; // A() has an empty body and
>> only trivial member initialization, so it's trivial
>>
>> private:
>>   int i = 20; // essentially pointless NSDMI for this type
>> };
>>
>>
>> The default constructor for A would then override its i member
>> initializer to be uninitialized and allow the body to be generated by the
>> compiler and hence detected in this case as being trivial.
>>
>
> And if I add a second member variable with a DMI, then I have to
> `default_init` that too. And if I add a third, I have to `default_init`
> that too. Otherwise, I change the semantics of the type. *Silently*. Or
> if not silently, then likely far from the place where I made the mistake.
>
> If my goal is to create an uninitializing constructor, I fail to see why I
> should have to explicitly mark every subobject to be uninitialized, when I
> can just mark the constructor itself. After all, that's what behavior I'm
> requesting.
>
> That's the problem sometimes with a generic solution; it makes life harder
> on those looking for a specific solution.
>
> Now, perhaps `= default_init` is the wrong term. What you're really
>>> creating is an *uninitializing* constructor: a constructor that in
>>> theory performs no initialization. The only initialization it may perform
>>> is calling default constructors for subobjects that aren't trivially
>>> default constructible. But it would not invoke default member initializers.
>>>
>>> I think. I'm still fairly up in the air about what the semantics of
>>> these things should be (though they do need to be *able* to be
>>> different from `= default`). Maybe they should fail to compile if any
>>> subobjects are not trivially default constructible. Maybe it should be `=
>>> trivial`.
>>>
>>
>> I'm leaning towards =default because the idea isn't to be _specifically
>> for trivial objects_. Again, I can't stress enough that I want avoid
>> one-off features and aim for generality.
>>
>
>> My suggestion is to be a general facility that is a building block for
>> your default_init and for uninitialized construction and for making certain
>> meta-programming Just Work(tm) as trivial when and if the various SFINAE,
>> Concepts, and specializations may require it. Consider your example
>> previously, but replace the integer member with something "trickier":
>>
>> template <class T>
>> class A {
>> public:
>>   A(C<T> i) : m(i.foo()) = default; // this may or may not be trivial,
>> dependent on B(decltype(C<T>::foo()))
>>                                     // being trivial, but the body {}
>> will never be trivial
>>
>>
>> private:
>>   B<T> m;
>>
>>
> In the above type with C++ today or with just your default_init, there is
>> no way to define A::A that will ever be trivial, even if the member
>> initialize it invokes is trivial (say, C<T>::foo() might return a B<T>
>> const& which invokes a trivial copy constructor. That's because today, you
>> must put a body {} on the definition, which the compiler will never ever
>> interpret as trivial. That's a language limitation that has absolutely
>> nothing to do with either your or my user case and yet would be corrected
>> with my suggestion. Generality is good. :)
>>
>
> Like with the meaning of `= default`, it seems that we are thinking about
> two very different things with regard to the concept of "trivial". The
> following explains the standard's view of this concept.
>
> Trivial, when applied to default constructors, means that the type has
> vacuous initialization; that changes how its lifetime works, in accord with
> [basic.life]/1. A object with a trivial default constructor which undergoes
> default initialization is *uninitialized*. Taken together, this means
> that no code needs to be executed to default initialize the object. This is
> the entire point of having trivial default constructors as a language
> concept.
>
> Trivial, when applied to copy/move constructors/assignment, means that the
> type is effectively memcpy-able (if all of them are trivial/deleted). This
> is the minimum possible code for a type's copy/move operation that actually
> copies/moves the value representation. This is the entire point of having
> trivial copy/move constructors/assignment operators as a language concept.
>
> Trivial, when applied to destructors, again affects lifetime rules.
> Calling a trivial destructor doesn't even end the lifetime of the object.
> An object with a trivial destructor is just a piece of memory. Such a
> destructor does nothing. This is the entire point of having trivial
> destructors as a language concept.
>
> If the term "trivial" had a basic definition, then I would say it's this:
> a trivial operation is one that you can either ignore or bypass with a
> generic mechanism. Trivial default constructors are not necessary to be
> called to initialize the object. A trivially copyable class can be
> `memcpy`d instead of actually calling the copy/move. And trivially
> destructible types don't need to have destructors called on them at all.
>
> Given this definition, it makes absolutely no sense for a constructor
> which calls a user-provided function to be considered "trivial". It's not a
> matter of how you spell it in the syntax; the concept of a trivial
> operation calling a user-specified function is a contradiction in terms.
>
> But OK, let's expand the definition of a trivial constructor to encompass
> your `A(C<T>)`. So... what does that mean we can do with this function? We
> cannot initialize `A` through this constructor without calling it, since it
> has side-effects that *must* happen. If that were a copy-constructor, it
> would not make `memcpy` equivalent to calling the copy constructor since it
> has side-effects that `memcpy` cannot replicate. And so on.
>
> The generality you have created here accomplishes nothing. Declaring that
> `A(C<T>)` is a "trivial" constructor says nothing about that constructor's
> behavior. It has side-effects, so user code still must be called; as such,
> it cannot be bypassed in any way. So how is `A(C<T> i) : m(i.foo()) =
> default;` any different from `A(C<T> i) : m(i.foo()) {}`? What code would
> be legal on the `= default` version but not on the other?
>
> What good is the "generality" you have proposed here?
>
> In my personal and probably unimportant opinion a very key design goal for
>> languages is to aim for small reuable bits of functionality instead of
>> large chunks of purpose-built functionality. It's composable and emergent
>> rather than rigid and limited.
>>
>
> I don't agree with that. That sort of thinking leads to the worst aspects
> of Lua: complete un-interoperability. Lua has a fantastically generic
> object model with its tables, which you can use to build classes. But
> because the language doesn't define classes as a first-class construct,
> just the pieces needed to build them, everyone builds them *differently*.
> So you can't really derive from someone else's class. And if you can, you
> can't derive from two different people's classes in the same object. Not
> without writing a lot of forwarding boilerplate.
>
> But that's actually great for Lua's primary purpose: being embedded in
> applications. In such an environment, you can construct the specific
> functionality your Lua users need, and let it go with that. But that only
> works because the people using that environment are highly dependent on the
> provider of that environment. In a more open world, when you're pulling in
> libraries and modules from wherever, it's a recipe for chaos.
>
> The key questions to me for a language proposal are:
>
> 1: Is the problem the proposal says it solves important enough to be worth
> solving in the language?
>
> 2: Does the proposal actually solve that problem?
>
> 3: Are there any other problems near that domain which small tweaks to the
> proposal could solve?
>
> 4: Is there anything we could lose from the proposal while still solving
> the problem?
>
> 5: Are there other ways to solve this problem that might be better in some
> way?
>
> 6: Does the language feature mesh well with the existing language
> infrastructure and features?
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit https://groups.google.com/a/
> isocpp.org/d/topic/std-proposals/54K4WTb4EcU/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/
> isocpp.org/d/msgid/std-proposals/168ab676-be9f-44dd-
> 90de-cbe532cf0617%40isocpp.org
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/168ab676-be9f-44dd-90de-cbe532cf0617%40isocpp.org?utm_medium=email&utm_source=footer>
> .
>



--
Sean Middleditch
http://seanmiddleditch.com

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALQmNFj%2Bj8wPoHrp%2BknML%3DiszMFpk9qp7g-Z8BvtFi4oy6VWxg%40mail.gmail.com.

--001a114dae72a7d57305448bb901
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">You&#39;ve done your homework on this one. :)<div><br></di=
v><div>I can&#39;t entirely disagree with your 6 philosophies though those =
are getting into the point of belonging a different thread so I won&#39;t t=
ry to carry that torch here. :)</div></div><div class=3D"gmail_extra"><br><=
div class=3D"gmail_quote">On Sun, Dec 25, 2016 at 7:06 PM, Nicol Bolas <spa=
n dir=3D"ltr">&lt;<a href=3D"mailto:jmckesson@gmail.com" target=3D"_blank">=
jmckesson@gmail.com</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quo=
te" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr"><div><div class=3D"h5">On Sunday, December 25, 2016 at 5:=
07:37 PM UTC-5, Sean Middleditch wrote:<blockquote class=3D"gmail_quote" st=
yle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1=
ex"><div dir=3D"ltr">On Monday, December 19, 2016 at 8:45:11 AM UTC-8, Nico=
l Bolas wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-le=
ft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On M=
onday, December 19, 2016 at 1:43:29 AM UTC-5, Sean Middleditch wrote:<block=
quote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left=
:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On Saturday, December 17=
, 2016 at 8:26:26 AM UTC-8, Nicol Bolas wrote:<blockquote class=3D"gmail_qu=
ote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding=
-left:1ex"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div di=
r=3D"ltr"><div>Which makes me think: perhaps instead of making default_init=
_t *completely* magic we could instead loosen the rules for constructor to =
allow any constructor to have =3Ddefault instead of a body. The compiler ca=
n then easily determine if the constructor is trivial or not via the existi=
ng rules. All types could then have a &quot;magic&quot; constructor foo::fo=
o(std::default_init_t) : foo() =3D default; implicitly generated if the def=
ault constructor isn&#39;t deleted. This also makes the overload question I=
 posed much simpler to answer since the answer becomes implied. I think the=
 generality is a better design in (ahem 2) general, but in this case it als=
o means existing code (like mine) using a similar type/trick can just repla=
ce their empty constructor bodies with =3Ddefault to become trivial, just l=
ike we did with default constructors in C++11.<br></div></div></blockquote>=
<div><br>I <i>really</i> don&#39;t like this idea.<br><br>The whole point o=
f this feature is to permit a user to default initialize any type `T` by do=
ing `T t =3D default_init;`. Therefore, that statement must always be <i>eq=
uivalent</i> to `T t;`.<br></div></div></blockquote><div><br></div><div>Her=
e we&#39;ll disagree then. :)</div></div></blockquote><div><br>But... that&=
#39;s the problem domain I outlined: I have some type T, which is being ini=
tialized through some forwarded interface, and I want to invoke default ini=
tialization on it. That&#39;s not the problem that your method solves. It n=
ever actually invokes the rules of default initialization; you merely get t=
o call a constructor that maybe doesn&#39;t initialize the object&#39;s dat=
a.<br></div></div></blockquote><div><br></div><div>I get it&#39;s not the s=
ame. What I&#39;m getting at is that you can have two &quot;small&quot; fea=
tures combine into multiple bigger features, instead of needing to define t=
wo separate big features. :)</div><div>=C2=A0<br></div><blockquote class=3D=
"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc soli=
d;padding-left:1ex"><div dir=3D"ltr"><div><br>That&#39;s not the same thing=
.. For reasons you&#39;ll see next:<br><br></div><blockquote class=3D"gmail_=
quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddi=
ng-left:1ex"><div dir=3D"ltr"><div></div><div>The magic value approach sits=
 very poorly with me. I&#39;d prefer to minimize its impact on the language=
 to the smallest possible degree. I believe your use case can be achieve wi=
th nothing more than introducing the automatically generated constructor _i=
f_ there&#39;s also a way to note that forwarded constructors can inherit t=
riviality... which my added suggestions provides (and that suggestion provi=
des more use cases than just making your feature work, which implies that i=
t has relatively high value so far as the difficulty-to-usefulness ratio go=
es).</div></div></blockquote><div><br>OK, explain how I would do this witho=
ut compiler magic:<br><br><div style=3D"background-color:rgb(250,250,250);b=
order-color:rgb(187,187,187);border-style:solid;border-width:1px"><code><di=
v><span style=3D"color:#000">vector</span><span style=3D"color:#080">&lt;in=
t&gt;</span><span style=3D"color:#000"> v</span><span style=3D"color:#660">=
;</span><span style=3D"color:#000"><br>v</span><span style=3D"color:#660">.=
</span><span style=3D"color:#000">emplace_back</span><span style=3D"color:#=
660">(</span><span style=3D"color:#000">std</span><span style=3D"color:#660=
">::</span><span style=3D"color:#000">default_in<wbr>it</span><span style=
=3D"color:#660">);</span></div></code></div><br>This statement is going to =
call `allocator_traits::construct(a<wbr>, p, std::default_init)`. Which wil=
l eventually perform `new(p) int(std::default_init)`.<br><br>If `std::defau=
lt_init_t` is a regular type, that&#39;s a compile error. The only way to m=
ake this compile without compiler magic is to make `std::default_init_t` im=
plicitly convertible to a (presumably default-initialized) value of any bas=
ic type. But that causes all kinds of <i>other</i> problems.<br><br>So comp=
iler magic is going to have to happen, one way or another.<br></div></div><=
/blockquote><div><br></div><div>Certainly, which I acknowledged - the &quot=
;minimal&quot; magic would be to provide a std::default_init_t type for all=
 types (built-in or otherwise), but literally no other special rules regard=
ing the constructor signature. This isn&#39;t even a huge deal of magic sin=
ce we already have standard support for compiler-generated constructors (de=
fault, copy, and move, specifically). With the =3Ddefault feature, the defi=
nition of this generated std::default_init_t is also pretty much solved wit=
hout needing to add additional language for what default_init_t does into t=
he standard&#39;s grammar definition.</div><div><br></div><div>e.g., less m=
agic.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div di=
r=3D"ltr"><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margi=
n:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=
=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.=
8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>If y=
ou use this magic constructor method, users can now <i>override</i> `defaul=
t_init_t` initialization. That completely destroys the whole purpose of the=
 feature. `T t`; will always follow [dcl.init]/7, while `T t =3D default_in=
it;` is just like any other constructor call.<br></div></div></blockquote><=
div><br></div><div>Unless of course that&#39;s what the author of the libra=
ry wanted. Why shouldn&#39;t an expert library author be able to override t=
he constructor? There are valid use cases to be able to override just about=
 everything else, which is allowed. I don&#39;t think it&#39;s terribly imp=
ortant to be able to override it, but I&#39;m not sure what you&#39;re real=
ly buying in real-world utility by adding special cases here.</div></div></=
blockquote><div><br>The utility is that the code does what it says. It perf=
orms default initialization, as that is defined in the standard. Not &quot;=
whatever form of initialization the user has substituted for `default_init`=
..<br></div></div></blockquote><div><br></div><div>Fair. I&#39;m not convinc=
ed that&#39;s all that important given all the other overload magic tricks =
users can do, though.</div><div><br></div><div>If you are sure that there m=
ust be a non-overloadable way of specifying default values, then my bike-sh=
edding preference would be to avoid a magic library type for the purpose</d=
iv></div></blockquote></div></div><div><br>If there&#39;s no type, then you=
 cannot perform default initialization through `emplace`-like functions, no=
r can you have `vector` default-initialize its members. The only thing left=
 in the proposal at that point is just a way to default initialize objects =
we directly initialize. Which we <i>already have</i>. What we lack is a way=
 to <i>indirectly</i> invoke default initialization.<br><br>Without the typ=
e, the proposal is just dead weight.<br><br>That being said, since `default=
` is a keyword already, and one that surprisingly doesn&#39;t get used very=
 often, it might not be unreasonable to make it resolve to a prvalue expres=
sion of `std::default_init_t` type. Much like `nullptr`. But the default in=
itialization still has to key off of the expression&#39;s type, not merely =
the use of the keyword.<br><br></div><span class=3D""><blockquote class=3D"=
gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid=
;padding-left:1ex"><div dir=3D"ltr"><div>, e.g. maybe to just allow `defaul=
t` as an expression and to make the language have specific rules that the c=
onstructor A(default) is equivalent to A(). It would make your proposal fee=
l more like nullptr&#39;s place in the language and less like std::initiali=
zer_list (and yeah, I&#39;m salty still about the later and consider it a l=
anguage wart, but that&#39;s me).<br></div><div><br></div><div>That also ma=
kes it a lot more clear and non-magic about why it can&#39;t be overloaded:=
 it&#39;s much clearer that a declaration A::A(default) is just a synonym f=
or A::A() the same way that f(void) is a synonym for f(). I like consistent=
, clear, and obvious grammar. :)</div><div>=C2=A0</div><blockquote class=3D=
"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc soli=
d;padding-left:1ex"><div dir=3D"ltr"><div>I get what you&#39;re wanting. Yo=
u want `T t` to call a default constructor, while making `T t(something)` p=
erform the equivalent of actual &quot;default initialization&quot;.<br></di=
v></div></blockquote><blockquote class=3D"gmail_quote" style=3D"margin:0;ma=
rgin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"lt=
r"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc=
 solid;padding-left:1ex"><div dir=3D"ltr"><div><br>I would say that the way=
 to handle this is to permit a user to define a constructor which performs =
default initialization of the object&#39;s members. Like this:<br><br><div =
style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bo=
rder-style:solid;border-width:1px"><code><div><span style=3D"color:#008">st=
ruct</span><span style=3D"color:#000"> A<br></span><span style=3D"color:#66=
0">{</span><span style=3D"color:#000"><br>=C2=A0 A</span><span style=3D"col=
or:#660">()</span><span style=3D"color:#000"> </span><span style=3D"color:#=
800">/*non-trivial default construction*/</span><span style=3D"color:#000">=
<br>=C2=A0 A</span><span style=3D"color:#660">(</span><span style=3D"color:=
#000">uninitialize_t</span><span style=3D"color:#660">)</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">=3D</span><span style=3D=
"color:#000"> default_init</span><span style=3D"color:#660">;</span><span s=
tyle=3D"color:#000"><br></span><span style=3D"color:#660">};</span></div></=
code></div><br>The code generated for that constructor will default initial=
ize its subobjects, overriding all default member initializers and such. If=
 one of the subobjects is not trivially default constructible, then this fu=
nction will not be a trivial constructor. If one of the subobjects cannot u=
ndergo default initialization (deleted default constructor, a reference, et=
c), this definition will be il-formed.<br></div></div></blockquote><div><br=
></div><div>Yeah, that too, though I see no reason why it needs to be a new=
 =3Ddefault_init instead of just =3Ddefault.</div><div><br></div><div>Remem=
ber that A::A() =3D default; is perfectly legal. Extending that to A::A(foo=
) =3D default or A::A(foo) : A() =3D default is a small step. The =3Ddefaul=
t basically translates to &quot;ignore implicit supression if present and s=
upply a trivial empty body; if all other invoked member initializations, im=
plicit or explicit, are trivial, then this is trivial as well.&quot;</div><=
/div></blockquote><div><br>But that&#39;s not what `=3D default` means. Def=
aulting a copy constructor does not &quot;supply a trivial empty body&quot;=
; it supplies a <i>real</i> function definition that may or may not be triv=
ial depending on what that definition has to do.<br></div></div></blockquot=
e><div><br></div><div>Well understood, and I&#39;ve not (intentionally) tri=
ed to imply anything else. :)</div><div>=C2=A0</div><blockquote class=3D"gm=
ail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;p=
adding-left:1ex"><div dir=3D"ltr"><div>The reason to go with a new term rat=
her than `=3D default` is so that it can have different semantics from `=3D=
 default`. If you `=3D default` a default constructor, the default member i=
nitializers are still invoked. Whereas if you `=3D default_init` it, then t=
he DMI&#39;s are <i>ignored</i>.<br></div></div></blockquote><div><br></div=
><div>I think that&#39;s particularly dangerous.</div><div><br></div><div>I=
t&#39;s a very muddled place between `A::A() =3D default` and `A::A() =3D d=
efault_init` having wildly different and potentially disastrously different=
 semantics.</div><div><br></div><div>Explicit beats implicit. If I want to =
override a DMI, the language already provides a way to do so: supply an ini=
tializer in the constructor. That&#39;s the place where I should opt in (on=
 a member-by-member basis) which initializers to suppress.</div><div><br></=
div><div>A::A() : x(default_init) =3D meow_whatever_allows_this_to_b<wbr>e_=
trivial_meow;</div></div></blockquote></span><div><br>Here&#39;s the proble=
m I have with this. The current rules state the following:<br><br>1: Member=
 initialization lists are part of a constructor&#39;s definition. That&#39;=
s why function-level try/catch blocks can catch exceptions thrown by subobj=
ect initialization.<br>2: `=3D default` is the totality of a constructor&#3=
9;s definition.<br>3: A constructor is user-provided if the user has given =
it a definition that isn&#39;t defaulted.<br>4: A constructor which is user=
-provided cannot be trivial.<br><br>In order for this syntax to have the ef=
fect you want, <i>at least one</i> of these rules must change.<br><br>Rules=
 #1&amp;2 are built into C++&#39;s <i>grammar</i>. Take a look at [dcl.fct.=
def.general]/1. `function-definition` includes `function-body`. And `functi=
on-body` <i>either</i> has `ctor-initializer` followed by `compound-stateme=
nt`, or it has `=3D default/delete` (or a function-try/catch block). Gramma=
tically, it is impossible to have both `=3D default` and member initializer=
s.<br><br>Obviously grammar can be changed; you could stick an optional `ct=
or-initializer` in front of `=3D default`. But that&#39;s part of my point;=
 your way requires a significant restructuring of all of these rules. It in=
creases complexity for both the standard and the user. It now has to say wh=
at it means to `=3D default` and provide initializers. What does that mean =
for copy/move constructors, for example?<br><br>And most important of all, =
what are the rules for when a constructor is &quot;user-provided&quot;? Rig=
ht now, the rules are fairly simple: it&#39;s user-provided if the type has=
 DMIs, virtuals, or if the constructor&#39;s definition is anything other t=
han `=3D default/delete`. Now, you have to add rules saying that user-provi=
ded constructors can have DMI&#39;d members, but all of those members must =
be explicitly default initialized for that constructor with `default_init`.=
 And it has to use that <i>exact</i> expression: `std::default_init` itself=
.. It cannot use some expression which evaluates to an object of type `std::=
default_init_t` (for reasons I&#39;ll explain below).<br><br>My way simply =
adds `=3D default_init` to `function-body` and to the list of the user-prov=
ided rules.<br><br>Now to be fair, it does add some other things here and t=
here. Namely, that an object which has a constructor that is an uninitializ=
ing constructor can undergo vacuous initialization ([basic.life]/1). Also, =
your type can be uninitializable if its subobjects can be unitialized, whet=
her through a trivial default constructor or a (public?) uninitializing con=
structor.<br><br>That is, consider this:<br><br><div style=3D"background-co=
lor:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;borde=
r-width:1px" class=3D"m_-4249000948755726912prettyprint"><code class=3D"m_-=
4249000948755726912prettyprint"><div class=3D"m_-4249000948755726912subpret=
typrint"><span style=3D"color:#008" class=3D"m_-4249000948755726912styled-b=
y-prettify">struct</span><span style=3D"color:#000" class=3D"m_-42490009487=
55726912styled-by-prettify"> </span><span style=3D"color:#606" class=3D"m_-=
4249000948755726912styled-by-prettify">Inner</span><span style=3D"color:#00=
0" class=3D"m_-4249000948755726912styled-by-prettify"><br></span><span styl=
e=3D"color:#660" class=3D"m_-4249000948755726912styled-by-prettify">{</span=
><span style=3D"color:#000" class=3D"m_-4249000948755726912styled-by-pretti=
fy"><br>=C2=A0 </span><span style=3D"color:#008" class=3D"m_-42490009487557=
26912styled-by-prettify">int</span><span style=3D"color:#000" class=3D"m_-4=
249000948755726912styled-by-prettify"> j </span><span style=3D"color:#660" =
class=3D"m_-4249000948755726912styled-by-prettify">=3D</span><span style=3D=
"color:#000" class=3D"m_-4249000948755726912styled-by-prettify"> </span><sp=
an style=3D"color:#066" class=3D"m_-4249000948755726912styled-by-prettify">=
5</span><span style=3D"color:#660" class=3D"m_-4249000948755726912styled-by=
-prettify">;</span><span style=3D"color:#000" class=3D"m_-42490009487557269=
12styled-by-prettify"><br><br>=C2=A0 </span><span style=3D"color:#606" clas=
s=3D"m_-4249000948755726912styled-by-prettify">Inner</span><span style=3D"c=
olor:#660" class=3D"m_-4249000948755726912styled-by-prettify">()</span><spa=
n style=3D"color:#000" class=3D"m_-4249000948755726912styled-by-prettify"> =
</span><span style=3D"color:#660" class=3D"m_-4249000948755726912styled-by-=
prettify">=3D</span><span style=3D"color:#000" class=3D"m_-4249000948755726=
912styled-by-prettify"> </span><span style=3D"color:#008" class=3D"m_-42490=
00948755726912styled-by-prettify">default</span><span style=3D"color:#660" =
class=3D"m_-4249000948755726912styled-by-prettify">;</span><span style=3D"c=
olor:#000" class=3D"m_-4249000948755726912styled-by-prettify"><br>=C2=A0 </=
span><span style=3D"color:#606" class=3D"m_-4249000948755726912styled-by-pr=
ettify">Inner</span><span style=3D"color:#660" class=3D"m_-4249000948755726=
912styled-by-prettify">(</span><span style=3D"color:#000" class=3D"m_-42490=
00948755726912styled-by-prettify">test</span><span style=3D"color:#660" cla=
ss=3D"m_-4249000948755726912styled-by-prettify">)</span><span style=3D"colo=
r:#000" class=3D"m_-4249000948755726912styled-by-prettify"> </span><span st=
yle=3D"color:#660" class=3D"m_-4249000948755726912styled-by-prettify">=3D</=
span><span style=3D"color:#000" class=3D"m_-4249000948755726912styled-by-pr=
ettify"> default_init</span><span style=3D"color:#660" class=3D"m_-42490009=
48755726912styled-by-prettify">;</span><span style=3D"color:#000" class=3D"=
m_-4249000948755726912styled-by-prettify"> </span><span style=3D"color:#800=
" class=3D"m_-4249000948755726912styled-by-prettify">//I really would prefe=
r `uninit`, which could be a special identifier.</span><span style=3D"color=
:#000" class=3D"m_-4249000948755726912styled-by-prettify"><br></span><span =
style=3D"color:#660" class=3D"m_-4249000948755726912styled-by-prettify">};<=
/span><span style=3D"color:#000" class=3D"m_-4249000948755726912styled-by-p=
rettify"><br><br></span><span style=3D"color:#008" class=3D"m_-424900094875=
5726912styled-by-prettify">struct</span><span style=3D"color:#000" class=3D=
"m_-4249000948755726912styled-by-prettify"> </span><span style=3D"color:#60=
6" class=3D"m_-4249000948755726912styled-by-prettify">Outer</span><span sty=
le=3D"color:#000" class=3D"m_-4249000948755726912styled-by-prettify"><br></=
span><span style=3D"color:#660" class=3D"m_-4249000948755726912styled-by-pr=
ettify">{</span><span style=3D"color:#000" class=3D"m_-4249000948755726912s=
tyled-by-prettify"><br>=C2=A0 </span><span style=3D"color:#606" class=3D"m_=
-4249000948755726912styled-by-prettify">Inner</span><span style=3D"color:#0=
00" class=3D"m_-4249000948755726912styled-by-prettify"> i</span><span style=
=3D"color:#660" class=3D"m_-4249000948755726912styled-by-prettify">;</span>=
<span style=3D"color:#000" class=3D"m_-4249000948755726912styled-by-prettif=
y"><br><br>=C2=A0 </span><span style=3D"color:#606" class=3D"m_-42490009487=
55726912styled-by-prettify">Outer</span><span style=3D"color:#660" class=3D=
"m_-4249000948755726912styled-by-prettify">()</span><span style=3D"color:#0=
00" class=3D"m_-4249000948755726912styled-by-prettify"> </span><span style=
=3D"color:#660" class=3D"m_-4249000948755726912styled-by-prettify">=3D</spa=
n><span style=3D"color:#000" class=3D"m_-4249000948755726912styled-by-prett=
ify"> </span><span style=3D"color:#008" class=3D"m_-4249000948755726912styl=
ed-by-prettify">default</span><span style=3D"color:#660" class=3D"m_-424900=
0948755726912styled-by-prettify">;</span><span style=3D"color:#000" class=
=3D"m_-4249000948755726912styled-by-prettify"> =C2=A0</span><span style=3D"=
color:#800" class=3D"m_-4249000948755726912styled-by-prettify">//Also, coul=
d use `default_init` to guarantee triviality.</span><span style=3D"color:#0=
00" class=3D"m_-4249000948755726912styled-by-prettify"><br></span><span sty=
le=3D"color:#660" class=3D"m_-4249000948755726912styled-by-prettify">};</sp=
an></div></code></div><br>`Inner` is not trivially default constructible, b=
y design. But it does have an accessible uninitializing constructor. And th=
erefore, the type is &quot;uninitializable&quot;. As such, `Outer` is allow=
ed to be trivially default constructible. Logically, it initializes `Outer:=
:i` by calling the uninitializing constructor of `Inner`. Of course in actu=
ality it will do nothing.<br><br>Basically, by having an accessible uniniti=
alizing constructor, you&#39;re saying that it&#39;s OK for this type to be=
 uninitialized. So you don&#39;t care if the constructor is called, and you=
 have no way to test if it&#39;s called since the compiler &quot;writes&quo=
t; the definition for it.<br><br>Of course, that last bit is not entirely t=
rue; the construction and destruction of the uninitializing constructor&#39=
;s parameter(s) could provoke side effects. But I consider eliding those to=
 be OK; if you make a public uninitializing constructor, then you are conse=
nting to it being used in this way.<br><br></div><span class=3D""><blockquo=
te class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div></div><div>I&#39;m not=
 married to =3Ddefault but it seems the best choice, since it already has t=
he desired meaning and semantics, only it&#39;s just not allowed outside of=
 a handful of limited places. This is similar to the comparison operations =
being discussed that allow them to be =3Ddefault even though the generated =
body will be something specific to the function being defaulted.</div><div>=
<br></div><div>In this case, =3Ddefault on a constructor - other than the c=
opy or move constructors - would just mean &quot;an empty body that may be =
trivial iff the member and base initializers are trivial.&quot; Which is at=
 its core the exact meaning you get today with =3Ddefault on the default co=
nstructor, so it&#39;s consistent and already well-understood and doesn&#39=
;t require new concepts or keywords or rules to be taught - it&#39;s just a=
 generalization of =3Ddefault. :)</div></div></blockquote></span><div><br><=
span class=3D"">But that&#39;s not what `=3D default` means.<br><br></span>=
From the standard, the purpose of `=3D default` is to make the compiler gen=
erate the code and behavior that it would have generated if not for the pre=
sence of other user-provided special member functions. It&#39;s not about h=
aving &quot;an empty body,&quot; it&#39;s about making sure a copy construc=
tor still gets generated, even though you&#39;ve provided a move constructo=
r (which would have prevented it from being generated).<br><br></div><span =
class=3D""><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:=
0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div></=
div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;b=
order-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>Furthermo=
re, if you `=3D default` a default constructor, but one of the subobjects c=
annot be default constructed, then the default constructor is internally `=
=3D delete`d. That&#39;s not the behavior we want when using `=3D default_i=
nit`; if the type cannot be default initialized, then the code should be il=
l-formed.<br></div></div></blockquote><div><br></div><div>I&#39;m missing t=
he distinction here, I think.</div></div></blockquote></span><div><br>OK, I=
 said that wrong.<br><br>Let&#39;s say you have a type `A` which can be def=
ault constructed, but its members always initialized to specific values. Th=
at is, it has a user-provided default constructor.<br><br>Now, let&#39;s sa=
y you have this:<br><br><div style=3D"background-color:rgb(250,250,250);bor=
der-color:rgb(187,187,187);border-style:solid;border-width:1px" class=3D"m_=
-4249000948755726912prettyprint"><code class=3D"m_-4249000948755726912prett=
yprint"><div class=3D"m_-4249000948755726912subprettyprint"><span style=3D"=
color:#008" class=3D"m_-4249000948755726912styled-by-prettify">struct</span=
><span style=3D"color:#000" class=3D"m_-4249000948755726912styled-by-pretti=
fy"> B<br></span><span style=3D"color:#660" class=3D"m_-4249000948755726912=
styled-by-prettify">{</span><span style=3D"color:#000" class=3D"m_-42490009=
48755726912styled-by-prettify"><br>=C2=A0 A a</span><span style=3D"color:#6=
60" class=3D"m_-4249000948755726912styled-by-prettify">;</span><span style=
=3D"color:#000" class=3D"m_-4249000948755726912styled-by-prettify"><br>=C2=
=A0 B</span><span style=3D"color:#660" class=3D"m_-4249000948755726912style=
d-by-prettify">()</span><span style=3D"color:#000" class=3D"m_-424900094875=
5726912styled-by-prettify"> a</span><span style=3D"color:#660" class=3D"m_-=
4249000948755726912styled-by-prettify">(</span><span style=3D"color:#000" c=
lass=3D"m_-4249000948755726912styled-by-prettify">std</span><span style=3D"=
color:#660" class=3D"m_-4249000948755726912styled-by-prettify">::</span><sp=
an style=3D"color:#000" class=3D"m_-4249000948755726912styled-by-prettify">=
default_init</span><span style=3D"color:#660" class=3D"m_-42490009487557269=
12styled-by-prettify">)</span><span style=3D"color:#000" class=3D"m_-424900=
0948755726912styled-by-prettify"> </span><span style=3D"color:#660" class=
=3D"m_-4249000948755726912styled-by-prettify">=3D</span><span style=3D"colo=
r:#000" class=3D"m_-4249000948755726912styled-by-prettify"> </span><span st=
yle=3D"color:#008" class=3D"m_-4249000948755726912styled-by-prettify">defau=
lt</span><span style=3D"color:#660" class=3D"m_-4249000948755726912styled-b=
y-prettify">;</span><span style=3D"color:#000" class=3D"m_-4249000948755726=
912styled-by-prettify"> </span><span style=3D"color:#800" class=3D"m_-42490=
00948755726912styled-by-prettify">//Your way</span><span style=3D"color:#00=
0" class=3D"m_-4249000948755726912styled-by-prettify"><br>=C2=A0 B</span><s=
pan style=3D"color:#660" class=3D"m_-4249000948755726912styled-by-prettify"=
>()</span><span style=3D"color:#000" class=3D"m_-4249000948755726912styled-=
by-prettify"> </span><span style=3D"color:#660" class=3D"m_-424900094875572=
6912styled-by-prettify">=3D</span><span style=3D"color:#000" class=3D"m_-42=
49000948755726912styled-by-prettify"> default_init</span><span style=3D"col=
or:#660" class=3D"m_-4249000948755726912styled-by-prettify">;</span><span s=
tyle=3D"color:#000" class=3D"m_-4249000948755726912styled-by-prettify"> </s=
pan><span style=3D"color:#800" class=3D"m_-4249000948755726912styled-by-pre=
ttify">//My way.</span><span style=3D"color:#000" class=3D"m_-4249000948755=
726912styled-by-prettify"><br></span><span style=3D"color:#660" class=3D"m_=
-4249000948755726912styled-by-prettify">};</span><span style=3D"color:#000"=
 class=3D"m_-4249000948755726912styled-by-prettify"><br></span></div></code=
></div><br>The result of your way is... nothing. `B::a` will still be initi=
alized, because `A` can be default initialized. What `A` cannot be is <i>un=
initialized</i>. Therefore, your default constructor will be non-trivial. I=
ndeed, you didn&#39;t even need `a(std::default_init)`, since that would ha=
ppen anyway.<br><br>The result of my way is a <i>compile error</i>. You ask=
ed `B` to declare a trivial constructor that would leave the object in an u=
ninitialized state. But one of its subobjects cannot be left in such a stat=
e. Therefore, you have contradicted yourself, so compilation must cease.<br=
><br>`=3D default` is not a request for a trivial default constructor; it i=
sn&#39;t even a request for <i>any</i> default constructor, since circumsta=
nces can leave it `delete`d. `=3D default_init` is a request for a trivial,=
 uninitializing constructor; if it cannot be trivial, then you asked for so=
mething the compiler can&#39;t give you, so you get an error.<br><br>So if =
you see a type with a `=3D default_init` constructor, you <i>know</i> the t=
ype can be uninitialized.<br><br></div><span class=3D""><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr"><div></div><blockquote class=3D"gma=
il_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pa=
dding-left:1ex"><div dir=3D"ltr"><div>There&#39;s a difference between thes=
e two classes:<br><br><div style=3D"background-color:rgb(250,250,250);borde=
r-color:rgb(187,187,187);border-style:solid;border-width:1px"><code><div><s=
pan style=3D"color:#008">class</span><span style=3D"color:#000"> A<br></spa=
n><span style=3D"color:#660">{</span><span style=3D"color:#000"><br></span>=
<span style=3D"color:#008">public</span><span style=3D"color:#660">:</span>=
<span style=3D"color:#000"><br>=C2=A0 A</span><span style=3D"color:#660">()=
</span><span style=3D"color:#000"> </span><span style=3D"color:#660">=3D</s=
pan><span style=3D"color:#000"> default_init</span><span style=3D"color:#66=
0">;</span><span style=3D"color:#000"><br><br></span><span style=3D"color:#=
008">private</span><span style=3D"color:#660">:</span><span style=3D"color:=
#000"><br>=C2=A0 </span><span style=3D"color:#008">int</span><span style=3D=
"color:#000"> i </span><span style=3D"color:#660">=3D</span><span style=3D"=
color:#000"> </span><span style=3D"color:#066">20</span><span style=3D"colo=
r:#660">;</span><span style=3D"color:#000"><br></span><span style=3D"color:=
#660">};</span><span style=3D"color:#000"><br><br></span><span style=3D"col=
or:#008">class</span><span style=3D"color:#000"> B<br></span><span style=3D=
"color:#660">{</span><span style=3D"color:#000"><br></span><span style=3D"c=
olor:#008">public</span><span style=3D"color:#660">:</span><span style=3D"c=
olor:#000"><br>=C2=A0 B</span><span style=3D"color:#660">()</span><span sty=
le=3D"color:#000"> </span><span style=3D"color:#660">=3D</span><span style=
=3D"color:#000"> </span><span style=3D"color:#008">default</span><span styl=
e=3D"color:#660">;</span><span style=3D"color:#000"><br><br></span><span st=
yle=3D"color:#008">private</span><span style=3D"color:#660">:</span><span s=
tyle=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">int</span>=
<span style=3D"color:#000"> i </span><span style=3D"color:#660">=3D</span><=
span style=3D"color:#000"> </span><span style=3D"color:#066">20</span><span=
 style=3D"color:#660">;</span><span style=3D"color:#000"><br></span><span s=
tyle=3D"color:#660">};</span></div></code></div><br>`B` will always initial=
ize its member, while `A()` will leave it uninitialized (though this will b=
e true even in value initialization, so it&#39;s probably not a good idea t=
o slap `=3D default_init` on a default constructor). This is asking for a d=
ifferent kind of code generation. So you should need to use a new syntax fo=
r that.<br></div></div></blockquote><div><br></div><div>A could also just b=
e given using my suggestion with something like:</div><div><br></div><block=
quote style=3D"margin:0 0 0 40px;border:none;padding:0px"><div><span style=
=3D"font-family:monospace;background-color:rgb(250,250,250);color:rgb(0,0,1=
36)">class</span><span style=3D"font-family:monospace;background-color:rgb(=
250,250,250);color:rgb(0,0,0)">=C2=A0A<br></span></div><div><span style=3D"=
font-family:monospace;background-color:rgb(250,250,250);color:rgb(102,102,0=
)">{</span></div><div><span style=3D"font-family:monospace;background-color=
:rgb(250,250,250);color:rgb(0,0,136)">public</span><span style=3D"font-fami=
ly:monospace;background-color:rgb(250,250,250);color:rgb(102,102,0)">:</spa=
n></div><div><span style=3D"font-family:monospace;background-color:rgb(250,=
250,250);color:rgb(0,0,0)">=C2=A0 A</span><span style=3D"font-family:monosp=
ace;background-color:rgb(250,250,250);color:rgb(102,102,0)">()</span><span =
style=3D"font-family:monospace;background-color:rgb(250,250,250);color:rgb(=
0,0,0)">=C2=A0: i{std::default_init}=C2=A0</span><span style=3D"font-family=
:monospace;background-color:rgb(250,250,250);color:rgb(102,102,0)">=3D</spa=
n><span style=3D"font-family:monospace;background-color:rgb(250,250,250);co=
lor:rgb(0,0,0)">=C2=A0default</span><span style=3D"font-family:monospace;ba=
ckground-color:rgb(250,250,250);color:rgb(102,102,0)"><wbr>; // A() has an =
empty body and only trivial member initialization, so it&#39;s trivial</spa=
n></div><div><span style=3D"font-family:monospace;background-color:rgb(250,=
250,250);color:rgb(0,0,0)"><br></span></div><div><span style=3D"font-family=
:monospace;background-color:rgb(250,250,250);color:rgb(0,0,136)">private</s=
pan><span style=3D"font-family:monospace;background-color:rgb(250,250,250);=
color:rgb(102,102,0)">:</span></div><div><span style=3D"font-family:monospa=
ce;background-color:rgb(250,250,250);color:rgb(0,0,0)">=C2=A0=C2=A0</span><=
span style=3D"font-family:monospace;background-color:rgb(250,250,250);color=
:rgb(0,0,136)">int</span><span style=3D"font-family:monospace;background-co=
lor:rgb(250,250,250);color:rgb(0,0,0)">=C2=A0i=C2=A0</span><span style=3D"f=
ont-family:monospace;background-color:rgb(250,250,250);color:rgb(102,102,0)=
">=3D</span><span style=3D"font-family:monospace;background-color:rgb(250,2=
50,250);color:rgb(0,0,0)">=C2=A0</span><span style=3D"font-family:monospace=
;background-color:rgb(250,250,250);color:rgb(0,102,102)">20</span><span sty=
le=3D"font-family:monospace;background-color:rgb(250,250,250);color:rgb(102=
,102,0)">; // essentially pointless NSDMI for this type</span></div><div><s=
pan style=3D"font-family:monospace;background-color:rgb(250,250,250);color:=
rgb(102,102,0)">};</span></div></blockquote><div>=C2=A0</div><div>The defau=
lt constructor for A would then override its i member initializer to be uni=
nitialized and allow the body to be generated by the compiler and hence det=
ected in this case as being trivial.</div></div></blockquote></span><div><b=
r>And if I add a second member variable with a DMI, then I have to `default=
_init` that too. And if I add a third, I have to `default_init` that too. O=
therwise, I change the semantics of the type. <i>Silently</i>. Or if not si=
lently, then likely far from the place where I made the mistake.<br><br>If =
my goal is to create an uninitializing constructor, I fail to see why I sho=
uld have to explicitly mark every subobject to be uninitialized, when I can=
 just mark the constructor itself. After all, that&#39;s what behavior I&#3=
9;m requesting.<br><br>That&#39;s the problem sometimes with a generic solu=
tion; it makes life harder on those looking for a specific solution.<br><br=
></div><span class=3D""><blockquote class=3D"gmail_quote" style=3D"margin:0=
;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D=
"ltr"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin=
-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><=
div>Now, perhaps `=3D default_init` is the wrong term. What you&#39;re real=
ly creating is an <i>uninitializing</i> constructor: a constructor that in =
theory performs no initialization. The only initialization it may perform i=
s calling default constructors for subobjects that aren&#39;t trivially def=
ault constructible. But it would not invoke default member initializers.<br=
><br>I think. I&#39;m still fairly up in the air about what the semantics o=
f these things should be (though they do need to be <i>able</i> to be diffe=
rent from `=3D default`). Maybe they should fail to compile if any subobjec=
ts are not trivially default constructible. Maybe it should be `=3D trivial=
`.<br></div></div></blockquote><div><br></div><div>I&#39;m leaning towards =
=3Ddefault because the idea isn&#39;t to be _specifically for trivial objec=
ts_. Again, I can&#39;t stress enough that I want avoid one-off features an=
d aim for generality.</div></div></blockquote><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,20=
4);padding-left:1ex"><div><br></div></blockquote><blockquote class=3D"gmail=
_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div dir=3D"ltr"><div></div><div>My suggestion is to be a gen=
eral facility that is a building block for your default_init and for uninit=
ialized construction and for making certain meta-programming Just Work(tm) =
as trivial when and if the various SFINAE, Concepts, and specializations ma=
y require it. Consider your example previously, but replace the integer mem=
ber with something &quot;trickier&quot;:</div><div><br></div><div style=3D"=
background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-styl=
e:solid;border-width:1px;word-wrap:break-word"><code><div><span style=3D"co=
lor:#008">template</span><span style=3D"color:#000"> </span><span style=3D"=
color:#660">&lt;</span><span style=3D"color:#008">class</span><span style=
=3D"color:#000"> T</span><span style=3D"color:#660">&gt;</span><span style=
=3D"color:#000"> <br></span><span style=3D"color:#008">class</span><span st=
yle=3D"color:#000"> A </span><span style=3D"color:#660">{</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#008">public</span><span st=
yle=3D"color:#660">:</span><span style=3D"color:#000"><br>=C2=A0 A</span><s=
pan style=3D"color:#660">(</span><span style=3D"color:#000">C</span><span s=
tyle=3D"color:#660">&lt;</span><span style=3D"color:#000">T</span><span sty=
le=3D"color:#660">&gt;</span><span style=3D"color:#000"> i</span><span styl=
e=3D"color:#660">)</span><span style=3D"color:#000"> </span><span style=3D"=
color:#660">:</span><span style=3D"color:#000"> m</span><span style=3D"colo=
r:#660">(</span><span style=3D"color:#000">i</span><span style=3D"color:#66=
0">.</span><span style=3D"color:#000">foo</span><span style=3D"color:#660">=
())</span><span style=3D"color:#000"> </span><span style=3D"color:#660">=3D=
</span><span style=3D"color:#000"> </span><span style=3D"color:#008">defaul=
t</span><span style=3D"color:#660">;</span><span style=3D"color:#000"> </sp=
an><span style=3D"color:#800">// this may or may not be trivial, dependent =
on B(decltype(C&lt;T&gt;::foo()))</span><span style=3D"color:#000"><br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"colo=
r:#800">// being trivial, but the body {} will never be trivial</span><span=
 style=3D"color:#000"><br><br><br></span><span style=3D"color:#008">private=
</span><span style=3D"color:#660">:</span><span style=3D"color:#000"><br>=
=C2=A0 B</span><span style=3D"color:#660">&lt;</span><span style=3D"color:#=
000">T</span><span style=3D"color:#660">&gt;</span><span style=3D"color:#00=
0"> m</span><span style=3D"color:#660">;</span></div></code></div><div>=C2=
=A0</div></div></blockquote><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div di=
r=3D"ltr"><div>In the above type with C++ today or with just your default_i=
nit, there is no way to define A::A that will ever be trivial, even if the =
member initialize it invokes is trivial (say, C&lt;T&gt;::foo() might retur=
n a B&lt;T&gt; const&amp; which invokes a trivial copy constructor. That&#3=
9;s because today, you must put a body {} on the definition, which the comp=
iler will never ever interpret as trivial. That&#39;s a language limitation=
 that has absolutely nothing to do with either your or my user case and yet=
 would be corrected with my suggestion. Generality is good. :)</div></div><=
/blockquote></span><div><br>Like with the meaning of `=3D default`, it seem=
s that we are thinking about two very different things with regard to the c=
oncept of &quot;trivial&quot;. The following explains the standard&#39;s vi=
ew of this concept.<br><br>Trivial, when applied to default constructors, m=
eans that the type has vacuous initialization; that changes how its lifetim=
e works, in accord with [basic.life]/1. A object with a trivial default con=
structor which undergoes default initialization is <i>uninitialized</i>. Ta=
ken together, this means that no code needs to be executed to default initi=
alize the object. This is the entire point of having trivial default constr=
uctors as a language concept.<br><br>Trivial, when applied to copy/move con=
structors/assignment, means that the type is effectively memcpy-able (if al=
l of them are trivial/deleted). This is the minimum possible code for a typ=
e&#39;s copy/move operation that actually copies/moves the value representa=
tion. This is the entire point of having trivial copy/move constructors/ass=
ignment operators as a language concept.<br><br>Trivial, when applied to de=
structors, again affects lifetime rules. Calling a trivial destructor doesn=
&#39;t even end the lifetime of the object. An object with a trivial destru=
ctor is just a piece of memory. Such a destructor does nothing. This is the=
 entire point of having trivial destructors as a language concept.<br><br>I=
f the term &quot;trivial&quot; had a basic definition, then I would say it&=
#39;s this: a trivial operation is one that you can either ignore or bypass=
 with a generic mechanism. Trivial default constructors are not necessary t=
o be called to initialize the object. A trivially copyable class can be `me=
mcpy`d instead of actually calling the copy/move. And trivially destructibl=
e types don&#39;t need to have destructors called on them at all.<br><br>Gi=
ven this definition, it makes absolutely no sense for a constructor which c=
alls a user-provided function to be considered &quot;trivial&quot;. It&#39;=
s not a matter of how you spell it in the syntax; the concept of a trivial =
operation calling a user-specified function is a contradiction in terms.<br=
><br>But OK, let&#39;s expand the definition of a trivial constructor to en=
compass your `A(C&lt;T&gt;)`. So... what does that mean we can do with this=
 function? We cannot initialize `A` through this constructor without callin=
g it, since it has side-effects that <i>must</i> happen. If that were a cop=
y-constructor, it would not make `memcpy` equivalent to calling the copy co=
nstructor since it has side-effects that `memcpy` cannot replicate. And so =
on.<br><br>The generality you have created here accomplishes nothing. Decla=
ring that `A(C&lt;T&gt;)` is a &quot;trivial&quot; constructor says nothing=
 about that constructor&#39;s behavior. It has side-effects, so user code s=
till must be called; as such, it cannot be bypassed in any way. So how is `=
A(C&lt;T&gt; i) : m(i.foo()) =3D default;` any different from `A(C&lt;T&gt;=
 i) : m(i.foo()) {}`? What code would be legal on the `=3D default` version=
 but not on the other?<br><br>What good is the &quot;generality&quot; you h=
ave proposed here?<br><br></div><span class=3D""><blockquote class=3D"gmail=
_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div dir=3D"ltr"><div></div><div>In my personal and probably =
unimportant opinion a very key design goal for languages is to aim for smal=
l reuable bits of functionality instead of large chunks of purpose-built fu=
nctionality. It&#39;s composable and emergent rather than rigid and limited=
..<br></div></div></blockquote></span><div><br>I don&#39;t agree with that. =
That sort of thinking leads to the worst aspects of Lua: complete un-intero=
perability. Lua has a fantastically generic object model with its tables, w=
hich you can use to build classes. But because the language doesn&#39;t def=
ine classes as a first-class construct, just the pieces needed to build the=
m, everyone builds them <i>differently</i>. So you can&#39;t really derive =
from someone else&#39;s class. And if you can, you can&#39;t derive from tw=
o different people&#39;s classes in the same object. Not without writing a =
lot of forwarding boilerplate.<br><br>But that&#39;s actually great for Lua=
&#39;s primary purpose: being embedded in applications. In such an environm=
ent, you can construct the specific functionality your Lua users need, and =
let it go with that. But that only works because the people using that envi=
ronment are highly dependent on the provider of that environment. In a more=
 open world, when you&#39;re pulling in libraries and modules from wherever=
, it&#39;s a recipe for chaos.<br><br>The key questions to me for a languag=
e proposal are:<br><br>1: Is the problem the proposal says it solves import=
ant enough to be worth solving in the language?<br><br>2: Does the proposal=
 actually solve that problem?<br><br>3: Are there any other problems near t=
hat domain which small tweaks to the proposal could solve?<br><br>4: Is the=
re anything we could lose from the proposal while still solving the problem=
?<br><br>5: Are there other ways to solve this problem that might be better=
 in some way?<br><br>6: Does the language feature mesh well with the existi=
ng language infrastructure and features?</div></div><span class=3D"">

<p></p>

-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups &quot;ISO C++ Standard - Future Proposals&quot; group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/54K4WTb4EcU/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/5=
4K4WTb4EcU/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br></span>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/168ab676-be9f-44dd-90de-cbe532cf0617%=
40isocpp.org?utm_medium=3Demail&amp;utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/<wbr>isocpp.org/d/msgid/std-<wbr>proposals/168a=
b676-be9f-44dd-<wbr>90de-cbe532cf0617%40isocpp.org</a><wbr>.<br>
</blockquote></div><br><br clear=3D"all"><div><br></div>-- <br><div class=
=3D"gmail_signature" data-smartmail=3D"gmail_signature">Sean Middleditch<br=
><a href=3D"http://seanmiddleditch.com" target=3D"_blank">http://seanmiddle=
ditch.com</a></div>
</div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CALQmNFj%2Bj8wPoHrp%2BknML%3DiszMFpk9=
qp7g-Z8BvtFi4oy6VWxg%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALQmNFj%2B=
j8wPoHrp%2BknML%3DiszMFpk9qp7g-Z8BvtFi4oy6VWxg%40mail.gmail.com</a>.<br />

--001a114dae72a7d57305448bb901--

.