220 30029 <3c0ceb25-43ac-478d-8794-6e37e4784cc7@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: Sean Middleditch <sean.middleditch@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: A Value for Default Initializing objects
Date: Sun, 25 Dec 2016 14:07:37 -0800 (PST)
Lines: 721
Approved: news@gmane.org
Message-ID: <3c0ceb25-43ac-478d-8794-6e37e4784cc7@isocpp.org>
References: <0be6b704-0bda-4706-85f9-e548bb3a3ef0@isocpp.org>
 <884e773c-e2d9-45db-9e0a-39029e0b32ab@isocpp.org>
 <ef39ea40-0732-449c-8aef-c0e85ab1457b@isocpp.org>
 <b851c076-a90b-446d-be90-bb832132f840@isocpp.org>
 <93bfc7e9-265b-4f6f-bf02-8a38d24675bf@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_3305_1083689784.1482703657491"
X-Trace: blaine.gmane.org 1482703664 8458 195.159.176.226 (25 Dec 2016 22:07:44 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Sun, 25 Dec 2016 22:07:44 +0000 (UTC)
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCDODCNR2QPRBKUGQHBQKGQED7K4PGY@isocpp.org Sun Dec 25 23:07:38 2016
Return-path: <std-proposals+bncBCDODCNR2QPRBKUGQHBQKGQED7K4PGY@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-pg0-f71.google.com ([74.125.83.71])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCDODCNR2QPRBKUGQHBQKGQED7K4PGY@isocpp.org>)
	id 1cLGx5-000197-4V
	for gclcip-std-proposals@m.gmane.org; Sun, 25 Dec 2016 23:07:35 +0100
Original-Received: by mail-pg0-f71.google.com with SMTP id n189sf301239031pga.4
        for <gclcip-std-proposals@m.gmane.org>; Sun, 25 Dec 2016 14:07:39 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=FufnF3Rgf2rrED5bTJeP78gshjhelZ0j7XepEiYuDBg=;
        b=VpbNPqZcU1EFVr84ThkzuX1b/svAVUCX1rm7lsIFe2XVOrO66vxnNjeDWMOMKJp/3R
         ldAkqmhOd6zdBKOVCXunnKwi/RcJSw+QVdGuD/Rwyq6IvfwG+pi/ZpIPOUONxgydW6f2
         hdKLBSQ8r0jhBuZLLZ0dqIxTSBlQq36CWpXLtY+/AiuX6rNAFqC/gJpOdvprXGr9xqov
         HlJWR5f6pPim9sUZFF6o8LHczmlqogtuNNmVNzZeLvOP7OamXDQWef8JbnAkDoK7q+7f
         eACXXcLWxA0fuGPoXN7mw7wM+7XnzQkoYpEszr7v/5Z77GMgjnAeX0HeGe5PRc4lenr+
         sbUw==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=FufnF3Rgf2rrED5bTJeP78gshjhelZ0j7XepEiYuDBg=;
        b=QK5J0gH+r9gFnSqtqpLmy1GjoCddvIO24EMfz0QxX0hbMykwZ9kzZHuZM2pyyHHNnp
         B1uPsxug1AMXP6kTcfEJiKhjQRR3kvjK91CK5WNyNFfZax7omwzKDQqNu43eVjuD0Dpo
         MFZdDcIRzeZMSPC8jGOInaQb7/UDTb0r2nvVi6Vx5DVzdXCQMXP1TmalOS4kxUT1IKax
         QRBIiENnlC+mmoJ1Tp/gehM+zq3R8KzPTDMGDWC/wUKwAUpox0m0UC5Db4N/jsxzE8IC
         SndLLxBj20mcNsjXIYD13NrONPu4PnX7P+gq/061eTjH5lpQZGz/npdKzcOzd+muOPWq
         Esyw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:date:from:to:message-id:in-reply-to:references
         :subject:mime-version:x-original-sender:reply-to:precedence
         :mailing-list:list-id:x-spam-checked-in-group:list-post:list-help
         :list-archive:list-subscribe:list-unsubscribe;
        bh=FufnF3Rgf2rrED5bTJeP78gshjhelZ0j7XepEiYuDBg=;
        b=tvDwyj89EGVh6W2gP5p4kMoLHNyRdvquzmohyLap2CV/aLcNonLhCh3KqSRwSG713S
         TKR6l7ZBl0OVIPRg45fWR0KjEoOXzIe5c1LE1CueGuoA39sqcIASc7fmi9myGx0sxHW2
         TbcenQmfaEJo6KMvJJPhOrOyp55xiHdscRe58qW2hP2ua1j2S4MVM5DiMpox7NB+l9+i
         Tz9epPa5FcLpjyMgBzQgl5d1rM0Y5oo2DSgDdKnWywU+DKBM85sbj1eyCGZd24WSfkzf
         OHPQ/r/+mCGREaCLXw0hc2+nXQhOmydh7lMXL72JvRP9uGUf5NP6xy1zql/lX6T5i1jN
         kbyw==
X-Gm-Message-State: AIkVDXLuhnbyTBGznuvRtg9YmmNrUU5QjTGtIRxWsX40QJWmAL1XDf3uH+dx1SuV9/4qQQ==
X-Received: by 10.99.112.92 with SMTP id a28mr13839726pgn.30.1482703659190;
        Sun, 25 Dec 2016 14:07:39 -0800 (PST)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.157.58.38 with SMTP id j35ls28258745otc.17.gmail; Sun, 25 Dec
 2016 14:07:38 -0800 (PST)
X-Received: by 10.157.11.142 with SMTP id 14mr1247902oth.20.1482703658314;
        Sun, 25 Dec 2016 14:07:38 -0800 (PST)
In-Reply-To: <93bfc7e9-265b-4f6f-bf02-8a38d24675bf@isocpp.org>
X-Original-Sender: Sean.Middleditch@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:30029
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/30029>

------=_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--

.
