Topic: Why is it required to have no private/protected
Author: Oleksandr Pikozh <o.pikozh@gmail.com>
Date: Thu, 11 Jan 2018 16:57:54 +0200
Raw View
Maybe I am missing something.
But from purely intuitive point of view, if this works=E2=80=A6
=C2=A0=C2=A0=C2=A0 class C {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1 i{1, 2}; ///<-=
-here
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 };
=E2=80=A6then these should also work:
* Example 1 "aggregate-initializing private members within the class=20
definition":
=C2=A0=C2=A0=C2=A0 class C1 {
=C2=A0=C2=A0=C2=A0 private:
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1 i{1, 2}; ///<-=
-here
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 };
* Example 2 "aggregate-initializing private members from a friend class":
=C2=A0=C2=A0=C2=A0 class C2 {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 friend C2H;
=C2=A0=C2=A0=C2=A0 private:
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
=C2=A0=C2=A0=C2=A0 };
=C2=A0=C2=A0=C2=A0 class C2H {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C2 i{1, 2}; ///<-=
-here
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 }
* Example 3 "aggregate-initializing protected members from a descendant=20
class":
=C2=A0=C2=A0=C2=A0 class C3 {
=C2=A0=C2=A0=C2=A0 protected:
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
=C2=A0=C2=A0=C2=A0 };
=C2=A0=C2=A0=C2=A0 class C3D: public C3 {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C3 i{1, 2}; ///<-=
-here
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
=C2=A0=C2=A0=C2=A0 }
I.e. it is reasonable that aggregate initialization cannot be performed=20
when it tries to affect unaccessible fields. And it is also reasonable=20
that aggregate initialization cannot be performed even when at least one=20
of the class fields is unaccessible. But why aggregate initialization is=20
blocked for classes whose all fields are accessible from the current=20
scope, I don't understand.
--=20
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 e=
mail 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/373e0b37-90e5-2de9-249c-e2fb95d908fe%40gmail.com=
..
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 11 Jan 2018 08:17:47 -0800 (PST)
Raw View
------=_Part_9063_1207158954.1515687467945
Content-Type: multipart/alternative;
boundary="----=_Part_9064_446307079.1515687467946"
------=_Part_9064_446307079.1515687467946
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Thursday, January 11, 2018 at 9:59:43 AM UTC-5, Oleksandr Pikozh wrote:
>
> Maybe I am missing something.=20
>
> But from purely intuitive point of view, if this works=E2=80=A6=20
>
> class C {=20
> public:=20
> int f1, f2;=20
> static void s() {=20
> C1 i{1, 2}; ///<--here=20
> }=20
> };=20
>
> =E2=80=A6then these should also work:=20
>
> * Example 1 "aggregate-initializing private members within the class=20
> definition":=20
>
> class C1 {=20
> private:=20
> int f1, f2;=20
> public:=20
> static void s() {=20
> C1 i{1, 2}; ///<--here=20
> }=20
> };=20
>
> * Example 2 "aggregate-initializing private members from a friend class":=
=20
>
> class C2 {=20
> public:=20
> friend C2H;=20
> private:=20
> int f1, f2;=20
> };=20
> class C2H {=20
> public:=20
> static void s() {=20
> C2 i{1, 2}; ///<--here=20
> }=20
> }=20
>
> * Example 3 "aggregate-initializing protected members from a descendant=
=20
> class":=20
>
> class C3 {=20
> protected:=20
> int f1, f2;=20
> };=20
> class C3D: public C3 {=20
> public:=20
> static void s() {=20
> C3 i{1, 2}; ///<--here=20
> }=20
> }=20
>
> I.e. it is reasonable that aggregate initialization cannot be performed=
=20
> when it tries to affect unaccessible fields. And it is also reasonable=20
> that aggregate initialization cannot be performed even when at least one=
=20
> of the class fields is unaccessible. But why aggregate initialization is=
=20
> blocked for classes whose all fields are accessible from the current=20
> scope, I don't understand.
>
There is no technical reason why it has to be this way (though the recent=
=20
`is_aggregate` trait would be made non-useful). But it's still not a good=
=20
idea.
First, the ordering of members in different access classes is undefined. So=
=20
you would only be able to expand this to classes where NSDMs are all of the=
=20
same access classes.
Second, this wouldn't work in real code.
Consider `C3`. Why are its members private?
If you wanted a type that could hold any two integers, but you couldn't=20
change them once set, you would just declare them `const` and leave them=20
public. But you made them mutable. And private.
Therefore, we must assume that you want to control the values of these two=
=20
integers. To do that, you need to have a user-provided constructor. And=20
once you have that, the type isn't an aggregate anymore.
See, the word "aggregate" was not chosen arbitrarily. The concept of=20
"aggregate" is exactly what the word means=20
<http://www.dictionary.com/browse/aggregate>: a thing made entirely of=20
other things. An aggregate currently is an assemblage of objects, each of=
=20
which can have any particular value which that subobject can store.
If you have a user-provided constructor, then the type isn't a mere=20
aggregation of things. Its member subobjects cannot assume any value;=20
you're controlling what values are legal for your object. Therefore, once=
=20
you have a constructor, the type isn't an aggregate anymore.
And if you don't have a constructor for `C1`, why are its members private?=
=20
What are you doing with classes with private members that have no=20
constructors?
--=20
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 e=
mail 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/9e80c7be-e2be-4945-a3ff-93886dd2b336%40isocpp.or=
g.
------=_Part_9064_446307079.1515687467946
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Thursday, January 11, 2018 at 9:59:43 AM UTC-5,=
Oleksandr Pikozh wrote:<blockquote class=3D"gmail_quote" style=3D"margin: =
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Maybe =
I am missing something.
<br>
<br>But from purely intuitive point of view, if this works=E2=80=A6
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1 i{1, =
2}; ///<--here
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>
<br>=E2=80=A6then these should also work:
<br>
<br>* Example 1 "aggregate-initializing private members within the cla=
ss=20
<br>definition":
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C1 {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 private:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1 i{1, =
2}; ///<--here
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>
<br>* Example 2 "aggregate-initializing private members from a friend =
class":
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C2 {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 friend C2H;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 private:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C2H {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C2 i{1, =
2}; ///<--here
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>=C2=A0=C2=A0=C2=A0=C2=A0 }
<br>
<br>* Example 3 "aggregate-initializing protected members from a desce=
ndant=20
<br>class":
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C3 {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 protected:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C3D: public C3 {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C3 i{1, =
2}; ///<--here
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>=C2=A0=C2=A0=C2=A0=C2=A0 }
<br>
<br>I.e. it is reasonable that aggregate initialization cannot be performed=
=20
<br>when it tries to affect unaccessible fields. And it is also reasonable=
=20
<br>that aggregate initialization cannot be performed even when at least on=
e=20
<br>of the class fields is unaccessible. But why aggregate initialization i=
s=20
<br>blocked for classes whose all fields are accessible from the current=20
<br>scope, I don't understand.<br></blockquote><div><br></div><div>Ther=
e is no technical reason why it has to be this way (though the recent `is_a=
ggregate` trait would be made non-useful). But it's still not a good id=
ea.</div><div><br></div><div>First, the ordering of members in different ac=
cess classes is undefined. So you would only be able to expand this to clas=
ses where NSDMs are all of the same access classes.</div><div><br></div><di=
v>Second, this wouldn't work in real code.</div><div><br></div><div>Con=
sider `C3`. Why are its members private?</div><div><br></div><div>If you wa=
nted a type that could hold any two integers, but you couldn't change t=
hem once set, you would just declare them `const` and leave them public. Bu=
t you made them mutable. And private.</div><div><br></div><div>Therefore, w=
e must assume that you want to control the values of these two integers. To=
do that, you need to have a user-provided constructor. And once you have t=
hat, the type isn't an aggregate anymore.</div><div><br></div><div>See,=
the word "aggregate" was not chosen arbitrarily. The concept of =
"aggregate" is exactly <a href=3D"http://www.dictionary.com/brows=
e/aggregate">what the word means</a>: a thing made entirely of other things=
.. An aggregate currently is an assemblage of objects, each of which can hav=
e any particular value which that subobject can store.</div><div><br></div>=
<div>If you have a user-provided constructor, then the type isn't a mer=
e aggregation of things. Its member subobjects cannot assume any value; you=
're controlling what values are legal for your object. Therefore, once =
you have a constructor, the type isn't an aggregate anymore.</div><div>=
<br></div><div>And if you don't have a constructor for `C1`, why are it=
s members private? What are you doing with classes with private members tha=
t have no constructors?</div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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/9e80c7be-e2be-4945-a3ff-93886dd2b336%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/9e80c7be-e2be-4945-a3ff-93886dd2b336=
%40isocpp.org</a>.<br />
------=_Part_9064_446307079.1515687467946--
------=_Part_9063_1207158954.1515687467945--
.
Author: Oleksandr Pikozh <o.pikozh@gmail.com>
Date: Thu, 11 Jan 2018 19:38:46 +0200
Raw View
This is a multi-part message in MIME format.
--------------87C8F21A4C1213DBD9276D21
Content-Type: text/plain; charset="UTF-8"; format=flowed
Content-Transfer-Encoding: quoted-printable
On 11.01.18 18:17, Nicol Bolas wrote:
>
>
> On Thursday, January 11, 2018 at 9:59:43 AM UTC-5, Oleksandr Pikozh=20
> wrote:
>
> Maybe I am missing something.
>
> But from purely intuitive point of view, if this works=E2=80=A6
>
> =C2=A0=C2=A0=C2=A0=C2=A0 class C {
> =C2=A0=C2=A0=C2=A0=C2=A0 public:
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1 i{1=
, 2}; ///<--here
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
> =C2=A0=C2=A0=C2=A0=C2=A0 };
>
> =E2=80=A6then these should also work:
>
> * Example 1 "aggregate-initializing private members within the class
> definition":
>
> =C2=A0=C2=A0=C2=A0=C2=A0 class C1 {
> =C2=A0=C2=A0=C2=A0=C2=A0 private:
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
> =C2=A0=C2=A0=C2=A0=C2=A0 public:
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1 i{1=
, 2}; ///<--here
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
> =C2=A0=C2=A0=C2=A0=C2=A0 };
>
> * Example 2 "aggregate-initializing private members from a friend
> class":
>
> =C2=A0=C2=A0=C2=A0=C2=A0 class C2 {
> =C2=A0=C2=A0=C2=A0=C2=A0 public:
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 friend C2H;
> =C2=A0=C2=A0=C2=A0=C2=A0 private:
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
> =C2=A0=C2=A0=C2=A0=C2=A0 };
> =C2=A0=C2=A0=C2=A0=C2=A0 class C2H {
> =C2=A0=C2=A0=C2=A0=C2=A0 public:
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C2 i{1=
, 2}; ///<--here
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
> =C2=A0=C2=A0=C2=A0=C2=A0 }
>
> * Example 3 "aggregate-initializing protected members from a
> descendant
> class":
>
> =C2=A0=C2=A0=C2=A0=C2=A0 class C3 {
> =C2=A0=C2=A0=C2=A0=C2=A0 protected:
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
> =C2=A0=C2=A0=C2=A0=C2=A0 };
> =C2=A0=C2=A0=C2=A0=C2=A0 class C3D: public C3 {
> =C2=A0=C2=A0=C2=A0=C2=A0 public:
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C3 i{1=
, 2}; ///<--here
> =C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
> =C2=A0=C2=A0=C2=A0=C2=A0 }
>
> I.e. it is reasonable that aggregate initialization cannot be
> performed
> when it tries to affect unaccessible fields. And it is also
> reasonable
> that aggregate initialization cannot be performed even when at
> least one
> of the class fields is unaccessible. But why aggregate
> initialization is
> blocked for classes whose all fields are accessible from the current
> scope, I don't understand.
>
>
> There is no technical reason why it has to be this way (though the=20
> recent `is_aggregate` trait would be made non-useful). But it's still=20
> not a good idea.
>
> First, the ordering of members in different access classes is=20
> undefined. So you would only be able to expand this to classes where=20
> NSDMs are all of the same access classes.
>
> Second, this wouldn't work in real code.
>
> Consider `C3`. Why are its members private?
>
> If you wanted a type that could hold any two integers, but you=20
> couldn't change them once set, you would just declare them `const` and=20
> leave them public. But you made them mutable. And private.
>
> Therefore, we must assume that you want to control the values of these=20
> two integers. To do that, you need to have a user-provided=20
> constructor. And once you have that, the type isn't an aggregate anymore.
>
> See, the word "aggregate" was not chosen arbitrarily. The concept of=20
> "aggregate" is exactly what the word means=20
> <http://www.dictionary.com/browse/aggregate>: a thing made entirely of=20
> other things. An aggregate currently is an assemblage of objects, each=20
> of which can have any particular value which that subobject can store.
>
> If you have a user-provided constructor, then the type isn't a mere=20
> aggregation of things. Its member subobjects cannot assume any value;=20
> you're controlling what values are legal for your object. Therefore,=20
> once you have a constructor, the type isn't an aggregate anymore.
>
> And if you don't have a constructor for `C1`, why are its members=20
> private? What are you doing with classes with private members that=20
> have no constructors?
Let me answer point-by-point.
> First, the ordering of members in different access classes is=20
> undefined. So you would only be able to expand this to classes where=20
> NSDMs are all of the same access classes.
Yes, undefined ordering of members in different access levels is a=20
problem. But it can be workarounded by less-strict restriction: if a=20
class has members of different access levels, allow it to be initialized=20
only with C++20 designated initializers (e.g. `A a{.x =3D 1, .y =3D2}`),=20
otherwise allow it to be initialized by both designated and=20
non-designated (e.g. `A a{1, 2}`) initializers. No need to forbid=20
aggregate initialization at all.
> Second, this wouldn't work in real code.
>
> Consider `C3`. Why are its members private?
Example C3 with protected members was purely theoretical (I provided it=20
just to describe concept in full). But the C2-like things (with friend=20
classes) often happen in my practice.
Idea is that C2 allows only certain combinations of field values. But=20
within the C2 itself there is not enough information to construct a new=20
(correct) combination (to check its correctness), that's why C2 itself=20
has no constructors. Instead it declares C2H as its friend and C2=20
instances are created within C2H. Due to prohibition of=20
private-aggregate construction I need to create a private identity=20
constructor (e.g. `private: C2(t1 v1, t2 v2, t3 v2): v1(v1), v2(v2),=20
v3(v3) {}`) inside every C2-like class to make it convenient to=20
construct it from within C2H; without that limitation I'd just use=20
aggregate construction for C2 within C2H (possibly deleting default=20
constructor of C2 with `C2() =3D delete;`, if needed).
For example, let C2 be iterator class and C2H be a container class.=20
Without information about owner-container, iterator is able to be only=20
default-constructed, but container constructs specific iterators:
=C2=A0=C2=A0=C2=A0 class my_container {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 using value_type =3D =E2=80=A6;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 class iterator {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 friend =
my_container;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 value_t=
ype &operator*() const;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 value_t=
ype *operator->() const;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=
=A6;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 private:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 t1 v1;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 t2 v2;
=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 iterator begin() {return {.v1 =
=3D =E2=80=A6; .v2 =3D =E2=80=A6;};} //OOPS
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator end() {return {.v1 =3D=
=E2=80=A6; .v2 =3D =E2=80=A6;};} //OOPS
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator find(=E2=80=A6) {=E2=
=80=A6; return {.v1 =3D =E2=80=A6; .v2 =3D =E2=80=A6;};} //OOPS
=C2=A0=C2=A0=C2=A0 };
Every such case currently needs a boilerplate constructor in inner=20
class. It would be nicer and more intuitive if they won't.
> See, the word "aggregate" was not chosen arbitrarily. The concept of=20
> "aggregate" is exactly what the word means=20
> <http://www.dictionary.com/browse/aggregate>: a thing made entirely of=20
> other things. An aggregate currently is an assemblage of objects, each=20
> of which can have any particular value which that subobject can store.
"Aggregateness" is actually a point-of-view-dependent thing. Things that=20
look like really secure black boxes from distant locations (e.g.=20
unrelated classes) always appear to be just a field-set from the close=20
distance (e.g. from within the class itself, from its friend-classes, etc).
> If you have a user-provided constructor, then the type isn't a mere=20
> aggregation of things.
The fact is that I HAVEN'T any user-provided constructor, because=20
C2-like classes cannot reliable construct themselves. Their=20
friend-classes construct them. Currently to construct them from friend=20
classes, we need some boilerplate code (either in C2: `private: C2(t1=20
v1, t2 v2, t3 v2): v1(v1), v2(v2), v3(v3) {}` instead of `C2() =3D=20
delete/default`; or in C2H: `C2 i; i.v1 =3D =E2=80=A6; i.v2 =3D =E2=80=A6; =
i.v3 =3D =E2=80=A6;=20
do_something(i);` instead of `do_something({=E2=80=A6})`).
> And if you don't have a constructor for `C1`, why are its members=20
> private? What are you doing with classes with private members that=20
> have no constructors?
C1-like things are more rare than C2-like. Still they also could happen=20
in practice. C1 could be a class that due to significantly-varying=20
construction conditions looks much clearer with construction via static=20
functions than with construction via constructors.
For example, let it be file_stream-like class (though it's probably not=20
the best example, but I can't right now imagine a better):
=C2=A0=C2=A0=C2=A0 class my_file_stream {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream() =3D delete;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static my_file_stream create_fi=
le(=E2=80=A6arguments=E2=80=A6);
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static my_file_stream open_file=
(=E2=80=A6arguments=E2=80=A6);
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;
=C2=A0=C2=A0=C2=A0 };
Of course can be workarounded with something like:
=C2=A0=C2=A0=C2=A0 class my_file_stream {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct file_creation_tag {=E2=
=80=A6};
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct file_opening_tag {=E2=80=
=A6};
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream(file_creation_ta=
g, =E2=80=A6arguments=E2=80=A6);
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream(file_opening_tag=
, =E2=80=A6arguments=E2=80=A6);
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;
=C2=A0=C2=A0=C2=A0 };
But=E2=80=A6 Ehh=E2=80=A6 It would be better to much better to allow both w=
ays.
Or C1 can prefer static-method-style construction due to other reasons, e.g=
:
=C2=A0=C2=A0=C2=A0 class C1 {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 C1() =3D delete;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static std::optional<C1> create=
_if_possible(=E2=80=A6);
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;
=C2=A0=C2=A0=C2=A0 };
--=20
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 e=
mail 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/1c50b848-8ddd-0c8a-4ecd-9ed5f069952c%40gmail.com=
..
--------------87C8F21A4C1213DBD9276D21
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8=
">
</head>
<body text=3D"#000000" bgcolor=3D"#FFFFFF">
<p><br>
</p>
<br>
<div class=3D"moz-cite-prefix">On 11.01.18 18:17, Nicol Bolas wrote:<br=
>
</div>
<blockquote type=3D"cite"
cite=3D"mid:9e80c7be-e2be-4945-a3ff-93886dd2b336@isocpp.org">
<div dir=3D"ltr"><br>
<br>
On Thursday, January 11, 2018 at 9:59:43 AM UTC-5, Oleksandr
Pikozh wrote:
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Maybe I
am missing something.
<br>
<br>
But from purely intuitive point of view, if this works=E2=80=A6
<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 class C {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1=
i{1, 2}; ///<--here
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>
<br>
=E2=80=A6then these should also work:
<br>
<br>
* Example 1 "aggregate-initializing private members within the
class <br>
definition":
<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 class C1 {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 private:
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1=
i{1, 2}; ///<--here
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>
<br>
* Example 2 "aggregate-initializing private members from a
friend class":
<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 class C2 {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 friend C2H;
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 private:
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 class C2H {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C2=
i{1, 2}; ///<--here
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 }
<br>
<br>
* Example 3 "aggregate-initializing protected members from a
descendant <br>
class":
<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 class C3 {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 protected:
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 class C3D: public C3 {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C3=
i{1, 2}; ///<--here
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>
=C2=A0=C2=A0=C2=A0=C2=A0 }
<br>
<br>
I.e. it is reasonable that aggregate initialization cannot be
performed <br>
when it tries to affect unaccessible fields. And it is also
reasonable <br>
that aggregate initialization cannot be performed even when at
least one <br>
of the class fields is unaccessible. But why aggregate
initialization is <br>
blocked for classes whose all fields are accessible from the
current <br>
scope, I don't understand.<br>
</blockquote>
<div><br>
</div>
<div>There is no technical reason why it has to be this way
(though the recent `is_aggregate` trait would be made
non-useful). But it's still not a good idea.</div>
<div><br>
</div>
<div>First, the ordering of members in different access classes
is undefined. So you would only be able to expand this to
classes where NSDMs are all of the same access classes.</div>
<div><br>
</div>
<div>Second, this wouldn't work in real code.</div>
<div><br>
</div>
<div>Consider `C3`. Why are its members private?</div>
<div><br>
</div>
<div>If you wanted a type that could hold any two integers, but
you couldn't change them once set, you would just declare them
`const` and leave them public. But you made them mutable. And
private.</div>
<div><br>
</div>
<div>Therefore, we must assume that you want to control the
values of these two integers. To do that, you need to have a
user-provided constructor. And once you have that, the type
isn't an aggregate anymore.</div>
<div><br>
</div>
<div>See, the word "aggregate" was not chosen arbitrarily. The
concept of "aggregate" is exactly <a
href=3D"http://www.dictionary.com/browse/aggregate"
moz-do-not-send=3D"true">what the word means</a>: a thing made
entirely of other things. An aggregate currently is an
assemblage of objects, each of which can have any particular
value which that subobject can store.</div>
<div><br>
</div>
<div>If you have a user-provided constructor, then the type
isn't a mere aggregation of things. Its member subobjects
cannot assume any value; you're controlling what values are
legal for your object. Therefore, once you have a constructor,
the type isn't an aggregate anymore.</div>
<div><br>
</div>
<div>And if you don't have a constructor for `C1`, why are its
members private? What are you doing with classes with private
members that have no constructors?</div>
</div>
</blockquote>
<br>
Let me answer point-by-point.<br>
<br>
<blockquote type=3D"cite">First, the ordering of members in different
access classes is undefined. So you would only be able to expand
this to classes where NSDMs are all of the same access classes.</bloc=
kquote>
<br>
Yes, undefined ordering of members in different access levels is a
problem. But it can be workarounded by less-strict restriction: if a
class has members of different access levels, allow it to be
initialized only with C++20 designated initializers (e.g. `A a{.x =3D
1, .y =3D2}`), otherwise allow it to be initialized by both designated
and non-designated (e.g. `A a{1, 2}`) initializers. No need to
forbid aggregate initialization at all.<br>
<br>
<blockquote type=3D"cite">
<div>Second, this wouldn't work in real code.</div>
<div><br>
</div>
<div>Consider `C3`. Why are its members private?</div>
</blockquote>
<br>
Example C3 with protected members was purely theoretical (I provided
it just to describe concept in full). But the C2-like things (with
friend classes) often happen in my practice.<br>
<br>
Idea is that C2 allows only certain combinations of field values.
But within the C2 itself there is not enough information to
construct a new (correct) combination (to check its correctness),
that's why C2 itself has no constructors. Instead it declares C2H as
its friend and C2 instances are created within C2H. Due to <span
id=3D"result_box" class=3D"short_text" lang=3D"en"><span class=3D"">p=
rohibition
of </span></span> private-aggregate construction I need to
create a private identity constructor (e.g. `private: C2(t1 v1, t2
v2, t3 v2): v1(v1), v2(v2), v3(v3) {}`) inside every C2-like class
to make it convenient to construct it from within C2H; without that
limitation I'd just use aggregate construction for C2 within C2H
(possibly deleting default constructor of C2 with `C2() =3D delete;`,
if needed).<br>
<br>
For example, let C2 be iterator class and C2H be a container class.
Without information about owner-container, iterator is able to be
only default-constructed, but container constructs specific
iterators:<br>
<br>
=C2=A0=C2=A0=C2=A0 class my_container {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 using value_type =3D =E2=80=
=A6;<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 class iterator {<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 frie=
nd my_container;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 valu=
e_type &operator*() const;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 valu=
e_type *operator->() const;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=
=80=A6;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 private:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 t1 v=
1;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 t2 v=
2;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 };<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator begin() {return {.v=
1 =3D =E2=80=A6; .v2 =3D =E2=80=A6;};} //OOPS<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator end() {return {.v1 =
=3D =E2=80=A6; .v2 =3D =E2=80=A6;};} //OOPS<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator find(=E2=80=A6) {=
=E2=80=A6; return {.v1 =3D =E2=80=A6; .v2 =3D =E2=80=A6;};} //OOPS<br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
Every such case currently needs a boilerplate constructor in inner
class. It would be nicer and more intuitive if they won't.<br>
<br>
<blockquote type=3D"cite">See, the word "aggregate" was not chosen
arbitrarily. The concept of "aggregate" is exactly <a
href=3D"http://www.dictionary.com/browse/aggregate">what the word
means</a>: a thing made entirely of other things. An aggregate
currently is an assemblage of objects, each of which can have any
particular value which that subobject can store.</blockquote>
<br>
"Aggregateness" is actually a point-of-view-dependent thing. Things
that look like really secure black boxes from distant locations
(e.g. unrelated classes) always appear to be just a field-set from
the close distance (e.g. from within the class itself, from its
friend-classes, etc).<br>
<br>
<blockquote type=3D"cite">If you have a user-provided constructor,
then the type isn't a mere aggregation of things.</blockquote>
<br>
The fact is that I HAVEN'T any user-provided constructor, because
C2-like classes cannot reliable construct themselves. Their
friend-classes construct them. Currently to construct them from
friend classes, we need some boilerplate code (either in C2:
`private: C2(t1 v1, t2 v2, t3 v2): v1(v1), v2(v2), v3(v3) {}`
instead of `C2() =3D delete/default`; or in C2H: `C2 i; i.v1 =3D =E2=80=
=A6; i.v2
=3D =E2=80=A6; i.v3 =3D =E2=80=A6; do_something(i);` instead of `do_som=
ething({=E2=80=A6})`).<br>
<br>
<blockquote type=3D"cite">And if you don't have a constructor for
`C1`, why are its members private? What are you doing with classes
with private members that have no constructors?</blockquote>
<br>
C1-like things are more rare than C2-like. Still they also could
happen in practice. C1 could be a class that due to
significantly-varying construction conditions looks much clearer
with construction via static functions than with construction via
constructors.<br>
<br>
For example, let it be file_stream-like class (though it's probably
not the best example, but I can't right now imagine a better):<br>
<br>
=C2=A0=C2=A0=C2=A0 class my_file_stream {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream() =3D delete;=
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static my_file_stream create=
_file(=E2=80=A6arguments=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static my_file_stream open_f=
ile(=E2=80=A6arguments=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
Of course can be workarounded with something like:<br>
<br>
=C2=A0=C2=A0=C2=A0 class my_file_stream {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct file_creation_tag {=
=E2=80=A6};<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct file_opening_tag {=E2=
=80=A6};<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream(file_creation=
_tag, =E2=80=A6arguments=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream(file_opening_=
tag, =E2=80=A6arguments=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
But=E2=80=A6 Ehh=E2=80=A6 It would be better to much better to allow bo=
th ways.<br>
<br>
Or C1 can prefer static-method-style construction due to other
reasons, e.g:<br>
<br>
=C2=A0=C2=A0=C2=A0 class C1 {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 C1() =3D delete;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static std::optional<C1&g=
t; create_if_possible(=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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/1c50b848-8ddd-0c8a-4ecd-9ed5f069952c%=
40gmail.com?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/1c50b848-8ddd-0c8a-4ecd-9ed5f069952c%=
40gmail.com</a>.<br />
--------------87C8F21A4C1213DBD9276D21--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 11 Jan 2018 10:17:28 -0800 (PST)
Raw View
------=_Part_658_561211532.1515694648698
Content-Type: multipart/alternative;
boundary="----=_Part_659_744532747.1515694648698"
------=_Part_659_744532747.1515694648698
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Thursday, January 11, 2018 at 12:39:06 PM UTC-5, Oleksandr Pikozh wrote:
>
> On 11.01.18 18:17, Nicol Bolas wrote:
> Let me answer point-by-point.
>
> First, the ordering of members in different access classes is undefined.=
=20
> So you would only be able to expand this to classes where NSDMs are all o=
f=20
> the same access classes.
>
>
> Yes, undefined ordering of members in different access levels is a=20
> problem. But it can be workarounded by less-strict restriction: if a clas=
s=20
> has members of different access levels, allow it to be initialized only=
=20
> with C++20 designated initializers (e.g. `A a{.x =3D 1, .y =3D2}`), other=
wise=20
> allow it to be initialized by both designated and non-designated (e.g. `A=
=20
> a{1, 2}`) initializers. No need to forbid aggregate initialization at all=
..
>
Designated initializers aren't allowed to break ordering. So if there is no=
=20
ordering in the case of different access classes, then there can be no=20
ordering with designated initializers either.
> See, the word "aggregate" was not chosen arbitrarily. The concept of=20
> "aggregate" is exactly what the word means=20
> <http://www.dictionary.com/browse/aggregate>: a thing made entirely of=20
> other things. An aggregate currently is an assemblage of objects, each of=
=20
> which can have any particular value which that subobject can store.
>
>
> "Aggregateness" is actually a point-of-view-dependent thing. Things that=
=20
> look like really secure black boxes from distant locations (e.g. unrelate=
d=20
> classes) always appear to be just a field-set from the close distance (e.=
g.=20
> from within the class itself, from its friend-classes, etc).
>
I understand that this is what you *want* to be the case. But that's a very=
=20
fundamental change in the very nature of a C++ concept. And I don't believe=
=20
it improves the language in a useful way.
Thus far, the principle advantage of this viewpoint is that you get to=20
avoid having to write one or more constructors that forward their=20
parameters. That improves DRY to a degree. And it does mesh well with=20
default member initializers.
But it seems to me that what you really want is a way to create=20
constructors that take parameters in the order that members are declared=20
and forward them directly to the appropriate subobjects. Aggregate=20
initialization is merely a means for you to achieve that.
Also, by defining a way in the language to create such constructor sets,=20
you also get to neatly sidestep the ordering problem of members of=20
different access classes. Because by definition in C++, all subobjcts of a=
=20
class are constructed in the order they appear in the class definition.=20
Since that ordering already exists, we can say that the order of parameters=
=20
to such a generated constructor must be the order they appear in the class,=
=20
so that they can be properly forwarded in that order.
Don't ask about what such a syntax might look like though. The best=20
strawman I could come up with is `type_name() =3D auto;`.
I think a type being an aggregate has to mean something more than a type=20
which has constructors that just so happen to forward parameters to its=20
subobjects.
> If you have a user-provided constructor, then the type isn't a mere=20
> aggregation of things.
>
>
> The fact is that I HAVEN'T any user-provided constructor, because C2-like=
=20
> classes cannot reliable construct themselves. Their friend-classes=20
> construct them.
>
That distinction makes absolutely no sense. Types with constructors do not=
=20
"construct themselves"; they are *always* constructed by someone else=20
calling the constructor and providing parameters.
=20
> Currently to construct them from friend classes, we need some boilerplate=
=20
> code (either in C2: `private: C2(t1 v1, t2 v2, t3 v2): v1(v1), v2(v2),=20
> v3(v3) {}` instead of `C2() =3D delete/default`; or in C2H: `C2 i; i.v1 =
=3D =E2=80=A6;=20
> i.v2 =3D =E2=80=A6; i.v3 =3D =E2=80=A6; do_something(i);` instead of `do_=
something({=E2=80=A6})`).
>
> And if you don't have a constructor for `C1`, why are its members private=
?=20
> What are you doing with classes with private members that have no=20
> constructors?
>
>
> C1-like things are more rare than C2-like. Still they also could happen i=
n=20
> practice. C1 could be a class that due to significantly-varying=20
> construction conditions looks much clearer with construction via static=
=20
> functions than with construction via constructors.
>
> For example, let it be file_stream-like class (though it's probably not=
=20
> the best example, but I can't right now imagine a better):
>
> class my_file_stream {
> public:
> my_file_stream() =3D delete;
> static my_file_stream create_file(=E2=80=A6arguments=E2=80=A6);
> static my_file_stream open_file(=E2=80=A6arguments=E2=80=A6);
> =E2=80=A6;
> };
>
> Of course can be workarounded with something like:
>
> class my_file_stream {
> public:
> struct file_creation_tag {=E2=80=A6};
> struct file_opening_tag {=E2=80=A6};
> my_file_stream(file_creation_tag, =E2=80=A6arguments=E2=80=A6);
> my_file_stream(file_opening_tag, =E2=80=A6arguments=E2=80=A6);
> =E2=80=A6;
> };
>
> But=E2=80=A6 Ehh=E2=80=A6 It would be better to much better to allow both=
ways.
>
Um, no it wouldn't. Why? Because in the latter case, I can call indirect=20
initialization functions like `make_shared`, `emplace_back` or whatever.=20
Through the constructor tag, I can have all the control of the static=20
functions, but I still get to construct the object in place without having=
=20
to do a move or whatever.
You could have the static/global functions as a slightly more convenient=20
interface, but that's just redundancy that serves little purpose.
Or C1 can prefer static-method-style construction due to other reasons, e.g=
:
>
> class C1 {
> public:
> C1() =3D delete;
> static std::optional<C1> create_if_possible(=E2=80=A6);
> =E2=80=A6;
> };
>
>
--=20
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 e=
mail 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/d939dc68-ce02-4b06-b26d-d6532f7961c6%40isocpp.or=
g.
------=_Part_659_744532747.1515694648698
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Thursday, January 11, 2018 at 12:39:06 PM UTC-5=
, Oleksandr Pikozh wrote:<blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<p>On 11.01.18 18:17, Nicol Bolas wrote:<br></p>
Let me answer point-by-point.<br>
<br>
<blockquote type=3D"cite">First, the ordering of members in different
access classes is undefined. So you would only be able to expand
this to classes where NSDMs are all of the same access classes.</bloc=
kquote>
<br>
Yes, undefined ordering of members in different access levels is a
problem. But it can be workarounded by less-strict restriction: if a
class has members of different access levels, allow it to be
initialized only with C++20 designated initializers (e.g. `A a{.x =3D
1, .y =3D2}`), otherwise allow it to be initialized by both designated
and non-designated (e.g. `A a{1, 2}`) initializers. No need to
forbid aggregate initialization at all.<br></div></blockquote><div><br>=
</div><div>Designated initializers aren't allowed to break ordering. So=
if there is no ordering in the case of different access classes, then ther=
e can be no ordering with designated initializers either.<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 bgcolor=3D"#FFFFFF" text=3D"#0000=
00">
<blockquote type=3D"cite">See, the word "aggregate" was not c=
hosen
arbitrarily. The concept of "aggregate" is exactly <a onmou=
sedown=3D"this.href=3D'http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.=
dictionary.com%2Fbrowse%2Faggregate\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjC=
NEH3WKo392YfXyomamMxKS1j1m9_Q';return true;" onclick=3D"this.href=3D=
9;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.dictionary.com%2Fbrowse%2=
Faggregate\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEH3WKo392YfXyomamMxKS1j1=
m9_Q';return true;" href=3D"http://www.dictionary.com/browse/aggregate"=
target=3D"_blank" rel=3D"nofollow">what the word
means</a>: a thing made entirely of other things. An aggregate
currently is an assemblage of objects, each of which can have any
particular value which that subobject can store.</blockquote>
<br>
"Aggregateness" is actually a point-of-view-dependent thing. =
Things
that look like really secure black boxes from distant locations
(e.g. unrelated classes) always appear to be just a field-set from
the close distance (e.g. from within the class itself, from its
friend-classes, etc).<br></div></blockquote><div><br></div><div>I under=
stand that this is what you <i>want</i> to be the case. But that's a ve=
ry fundamental change in the very nature of a C++ concept. And I don't =
believe it improves the language in a useful way.</div><div><br></div><div>=
Thus far, the principle advantage of this viewpoint is that you get to avoi=
d having to write one or more constructors that forward their parameters. T=
hat improves DRY to a degree. And it does mesh well with default member ini=
tializers.</div><div><br></div><div>But it seems to me that what you really=
want is a way to create constructors that take parameters in the order tha=
t members are declared and forward them directly to the appropriate subobje=
cts. Aggregate initialization is merely a means for you to achieve that.</d=
iv><div><br></div><div>Also, by defining a way in the language to create su=
ch constructor sets, you also get to neatly sidestep the ordering problem o=
f members of different access classes. Because by definition in C++, all su=
bobjcts of a class are constructed in the order they appear in the class de=
finition. Since that ordering already exists, we can say that the order of =
parameters to such a generated constructor must be the order they appear in=
the class, so that they can be properly forwarded in that order.</div><div=
><br></div><div>Don't ask about what such a syntax might look like thou=
gh. The best strawman I could come up with is `type_name() =3D auto;`.</div=
><div><br></div><div>I think a type being an aggregate has to mean somethin=
g more than a type which has constructors that just so happen to forward pa=
rameters to its subobjects.<br></div><blockquote class=3D"gmail_quote" styl=
e=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left:=
1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">If you have a user-provided constructor,
then the type isn't a mere aggregation of things.</blockquote>
<br>
The fact is that I HAVEN'T any user-provided constructor, because
C2-like classes cannot reliable construct themselves. Their
friend-classes construct them.</div></blockquote><div><br></div><div>Th=
at distinction makes absolutely no sense. Types with constructors do not &q=
uot;construct themselves"; they are <i>always</i> constructed by someo=
ne else calling the constructor and providing parameters.</div><div>=C2=A0<=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" =
text=3D"#000000">Currently to construct them from
friend classes, we need some boilerplate code (either in C2:
`private: C2(t1 v1, t2 v2, t3 v2): v1(v1), v2(v2), v3(v3) {}`
instead of `C2() =3D delete/default`; or in C2H: `C2 i; i.v1 =3D =E2=80=
=A6; i.v2
=3D =E2=80=A6; i.v3 =3D =E2=80=A6; do_something(i);` instead of `do_som=
ething({=E2=80=A6})`).<br>
<br>
<blockquote type=3D"cite">And if you don't have a constructor for
`C1`, why are its members private? What are you doing with classes
with private members that have no constructors?</blockquote>
<br>
C1-like things are more rare than C2-like. Still they also could
happen in practice. C1 could be a class that due to
significantly-varying construction conditions looks much clearer
with construction via static functions than with construction via
constructors.<br>
<br>
For example, let it be file_stream-like class (though it's probably
not the best example, but I can't right now imagine a better):<br>
<br>
=C2=A0=C2=A0=C2=A0 class my_file_stream {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream() =3D delete;=
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static my_file_stream create=
_file(=E2=80=A6arguments=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static my_file_stream open_f=
ile(=E2=80=A6arguments=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
Of course can be workarounded with something like:<br>
<br>
=C2=A0=C2=A0=C2=A0 class my_file_stream {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct file_creation_tag {=
=E2=80=A6};<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct file_opening_tag {=E2=
=80=A6};<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream(file_creation=
_<wbr>tag, =E2=80=A6arguments=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 my_file_stream(file_opening_=
<wbr>tag, =E2=80=A6arguments=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
But=E2=80=A6 Ehh=E2=80=A6 It would be better to much better to allow bo=
th ways.<br></div></blockquote><div><br></div><div>Um, no it wouldn't. =
Why? Because in the latter case, I can call indirect initialization functio=
ns like `make_shared`, `emplace_back` or whatever. Through the constructor =
tag, I can have all the control of the static functions, but I still get to=
construct the object in place without having to do a move or whatever.</di=
v><div><br></div><div>You could have the static/global functions as a sligh=
tly more convenient interface, but that's just redundancy that serves l=
ittle purpose.</div><div><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">Or C1 can prefer static-met=
hod-style construction due to other
reasons, e.g:<br>
<br>
=C2=A0=C2=A0=C2=A0 class C1 {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 C1() =3D delete;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static std::optional<C1&g=
t; create_if_possible(=E2=80=A6);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0 };<br>
<br>
</div>
</blockquote></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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/d939dc68-ce02-4b06-b26d-d6532f7961c6%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d939dc68-ce02-4b06-b26d-d6532f7961c6=
%40isocpp.org</a>.<br />
------=_Part_659_744532747.1515694648698--
------=_Part_658_561211532.1515694648698--
.
Author: Oleksandr Pikozh <o.pikozh@gmail.com>
Date: Thu, 11 Jan 2018 20:51:18 +0200
Raw View
This is a multi-part message in MIME format.
--------------A18538F642561D9590A1FCC5
Content-Type: text/plain; charset="UTF-8"; format=flowed
Content-Transfer-Encoding: quoted-printable
On 11.01.18 20:17, Nicol Bolas wrote:
> Designated initializers aren't allowed to break ordering. So if there=20
> is no ordering in the case of different access classes, then there can=20
> be no ordering with designated initializers either.
OK, I get it.
> But that's a very fundamental change in the very nature of a C++ concept.
OK.
> But it seems to me that what you really want is a way to create=20
> constructors that take parameters in the order that members are=20
> declared and forward them directly to the appropriate subobjects.=20
> Aggregate initialization is merely a means for you to achieve that.
>
> Also, by defining a way in the language to create such constructor=20
> sets, you also get to neatly sidestep the ordering problem of members=20
> of different access classes. Because by definition in C++, all=20
> subobjcts of a class are constructed in the order they appear in the=20
> class definition. Since that ordering already exists, we can say that=20
> the order of parameters to such a generated constructor must be the=20
> order they appear in the class, so that they can be properly forwarded=20
> in that order.
>
> Don't ask about what such a syntax might look like though. The best=20
> strawman I could come up with is `type_name() =3D auto;`.
Personally I would really want a way to explicitly enable/disable=20
aggregate-constructor syntax.
E.g. `type_name{} =3D default;` (with meaning "yeah, maybe I declared a=20
custom constructor for this, but I still want the aggregate-constructor=20
syntax for it (either publicly, or privately only)") and `type_name{} =3D=
=20
delete;`; and not to have it auto-disabled in unexpected cases.
However I understand that it may appear incompatible with existing C++=20
model.
> Types with constructors do not "construct themselves"; they are=20
> /always/ constructed by someone else calling the constructor and=20
> providing parameters.
Theoretically yes, class instances are always constructed by some outer=20
context.
But as in practice I strongly prefer=E2=80=A6
=C2=A0=C2=A0=C2=A0 class vector {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 class iterator {=E2=80=A6};
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator begin();
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator end();
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;
=C2=A0=C2=A0=C2=A0 };
=E2=80=A6over=E2=80=A6
=C2=A0=C2=A0=C2=A0 class vector {
=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 class iterator {
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 public:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct =
begin_tag {};
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct =
end_tag {};
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterato=
r(vector &, begin_tag);
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterato=
r(vector &, end_tag);
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0=C2=A0 =C2=A0 =E2=80=A6;
=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 =E2=80=A6;
=C2=A0=C2=A0=C2=A0 };
=E2=80=A6therefore I need somehow to differentiate classes that are constru=
cted=20
from outside primarily by constructors from classes that are constructed=20
from outside primarily by methods, so I used a quite-imprecise phrase=20
"construct themselves".
> Um, no it wouldn't. Why? Because in the latter case, I can call=20
> indirect initialization functions like `make_shared`, `emplace_back`=20
> or whatever. Through the constructor tag, I can have all the control=20
> of the static functions, but I still get to construct the object in=20
> place without having to do a move or whatever.
IMHO, that distinction between constructors and=20
nonvoid-returning-functions is one of greatest faults in C++ design=20
(however I understand that it's probably too late now to break it (the=20
distinction) in a compatible way).
OK, thanks for your attention.
--=20
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 e=
mail 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/cba3f7ac-22b1-8dde-c406-7be4c5d67055%40gmail.com=
..
--------------A18538F642561D9590A1FCC5
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8=
">
</head>
<body text=3D"#000000" bgcolor=3D"#FFFFFF">
On 11.01.18 20:17, Nicol Bolas wrote:<br>
<blockquote type=3D"cite"
cite=3D"mid:d939dc68-ce02-4b06-b26d-d6532f7961c6@isocpp.org">
<div dir=3D"ltr">Designated initializers aren't allowed to break
ordering. So if there is no ordering in the case of different
access classes, then there can be no ordering with designated
initializers either.<br>
</div>
</blockquote>
OK, I get it.<br>
<br>
<blockquote type=3D"cite">But that's a very fundamental change in the
very nature of a C++ concept.</blockquote>
OK.<br>
<br>
<blockquote type=3D"cite"
cite=3D"mid:d939dc68-ce02-4b06-b26d-d6532f7961c6@isocpp.org">
<div dir=3D"ltr">But it seems to me that what you really want is a
way to create constructors that take parameters in the order
that members are declared and forward them directly to the
appropriate subobjects. Aggregate initialization is merely a
means for you to achieve that.
<div><br>
</div>
<div>Also, by defining a way in the language to create such
constructor sets, you also get to neatly sidestep the ordering
problem of members of different access classes. Because by
definition in C++, all subobjcts of a class are constructed in
the order they appear in the class definition. Since that
ordering already exists, we can say that the order of
parameters to such a generated constructor must be the order
they appear in the class, so that they can be properly
forwarded in that order.</div>
<div><br>
</div>
<div>Don't ask about what such a syntax might look like though.
The best strawman I could come up with is `type_name() =3D
auto;`.</div>
</div>
</blockquote>
Personally I would really want a way to explicitly enable/disable
aggregate-constructor syntax.<br>
E.g. `type_name{} =3D default;` (with meaning "yeah, maybe I declared
a custom constructor for this, but I still want the
aggregate-constructor syntax for it (either publicly, or privately
only)") and `type_name{} =3D delete;`; and not to have it
auto-disabled in unexpected cases.<br>
However I understand that it may appear incompatible with existing
C++ model.<br>
<br>
<blockquote type=3D"cite"
cite=3D"mid:d939dc68-ce02-4b06-b26d-d6532f7961c6@isocpp.org">
<div dir=3D"ltr">Types with constructors do not "construct
themselves"; they are <i>always</i> constructed by someone else
calling the constructor and providing parameters.</div>
</blockquote>
Theoretically yes, class instances are always constructed by some
outer context.<br>
But as in practice I strongly prefer=E2=80=A6<br>
=C2=A0=C2=A0=C2=A0 class vector {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 class iterator {=E2=80=A6};<=
br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator begin();<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iterator end();<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0 };<br>
=E2=80=A6over=E2=80=A6<br>
=C2=A0=C2=A0=C2=A0 class vector {<br>
=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 class iterator {<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 public:<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 stru=
ct begin_tag {};<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 stru=
ct end_tag {};<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iter=
ator(vector &, begin_tag);<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 iter=
ator(vector &, end_tag);<br>
=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0=C2=A0 =C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 };<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=80=A6;<br>
=C2=A0=C2=A0=C2=A0 };<br>
=E2=80=A6therefore I need somehow to differentiate classes that are
constructed from outside primarily by constructors from classes that
are constructed from outside primarily by methods, so I used a
quite-imprecise phrase "construct themselves".<br>
<br>
<blockquote type=3D"cite"
cite=3D"mid:d939dc68-ce02-4b06-b26d-d6532f7961c6@isocpp.org">
<div dir=3D"ltr">Um, no it wouldn't. Why? Because in the latter
case, I can call indirect initialization functions like
`make_shared`, `emplace_back` or whatever. Through the
constructor tag, I can have all the control of the static
functions, but I still get to construct the object in place
without having to do a move or whatever.</div>
</blockquote>
IMHO, that distinction between constructors and
nonvoid-returning-functions is one of greatest faults in C++ design
(however I understand that it's probably too late now to break it
(the distinction) in a compatible way).<br>
<br>
OK, thanks for your attention.<br>
</body>
</html>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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/cba3f7ac-22b1-8dde-c406-7be4c5d67055%=
40gmail.com?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/cba3f7ac-22b1-8dde-c406-7be4c5d67055%=
40gmail.com</a>.<br />
--------------A18538F642561D9590A1FCC5--
.
Author: Edward Catmur <ed@catmur.co.uk>
Date: Thu, 11 Jan 2018 16:20:48 -0800 (PST)
Raw View
------=_Part_732_1303810768.1515716448332
Content-Type: multipart/alternative;
boundary="----=_Part_733_378975435.1515716448332"
------=_Part_733_378975435.1515716448332
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Thursday, 11 January 2018 16:17:48 UTC, Nicol Bolas wrote:
>
>
>
> On Thursday, January 11, 2018 at 9:59:43 AM UTC-5, Oleksandr Pikozh wrote=
:
>>
>> Maybe I am missing something.=20
>>
>> But from purely intuitive point of view, if this works=E2=80=A6=20
>>
>> class C {=20
>> public:=20
>> int f1, f2;=20
>> static void s() {=20
>> C1 i{1, 2}; ///<--here=20
>> }=20
>> };=20
>>
>> =E2=80=A6then these should also work:=20
>>
>> * Example 1 "aggregate-initializing private members within the class=20
>> definition":=20
>>
>> class C1 {=20
>> private:=20
>> int f1, f2;=20
>> public:=20
>> static void s() {=20
>> C1 i{1, 2}; ///<--here=20
>> }=20
>> };=20
>>
>> * Example 2 "aggregate-initializing private members from a friend class"=
:=20
>>
>> class C2 {=20
>> public:=20
>> friend C2H;=20
>> private:=20
>> int f1, f2;=20
>> };=20
>> class C2H {=20
>> public:=20
>> static void s() {=20
>> C2 i{1, 2}; ///<--here=20
>> }=20
>> }=20
>>
>> * Example 3 "aggregate-initializing protected members from a descendant=
=20
>> class":=20
>>
>> class C3 {=20
>> protected:=20
>> int f1, f2;=20
>> };=20
>> class C3D: public C3 {=20
>> public:=20
>> static void s() {=20
>> C3 i{1, 2}; ///<--here=20
>> }=20
>> }=20
>>
>> I.e. it is reasonable that aggregate initialization cannot be performed=
=20
>> when it tries to affect unaccessible fields. And it is also reasonable=
=20
>> that aggregate initialization cannot be performed even when at least one=
=20
>> of the class fields is unaccessible. But why aggregate initialization is=
=20
>> blocked for classes whose all fields are accessible from the current=20
>> scope, I don't understand.
>>
>
> There is no technical reason why it has to be this way (though the recent=
=20
> `is_aggregate` trait would be made non-useful). But it's still not a good=
=20
> idea.
>
> First, the ordering of members in different access classes is undefined.=
=20
> So you would only be able to expand this to classes where NSDMs are all o=
f=20
> the same access classes.
>
I don't see that the layout in-memory of a mixed-access class is relevant.=
=20
The logical ordering of members as observed by the sequence in which NSDMs=
=20
are constructed and (in reverse) destructed is still the same as the=20
overall lexical order of members within the class definition. Anyone who=20
has the poor taste to write a class with mixed-access NSDMs is unlikely to=
=20
expect the aggregate construction order to follow in-memory order over=20
lexical and runtime sequential order.
=20
> Second, this wouldn't work in real code.
>
> Consider `C3`. Why are its members private?
>
> If you wanted a type that could hold any two integers, but you couldn't=
=20
> change them once set, you would just declare them `const` and leave them=
=20
> public. But you made them mutable. And private.
>
> Therefore, we must assume that you want to control the values of these tw=
o=20
> integers. To do that, you need to have a user-provided constructor. And=
=20
> once you have that, the type isn't an aggregate anymore.
>
> See, the word "aggregate" was not chosen arbitrarily. The concept of=20
> "aggregate" is exactly what the word means=20
> <http://www.dictionary.com/browse/aggregate>: a thing made entirely of=20
> other things. An aggregate currently is an assemblage of objects, each of=
=20
> which can have any particular value which that subobject can store.
>
> If you have a user-provided constructor, then the type isn't a mere=20
> aggregation of things. Its member subobjects cannot assume any value;=20
> you're controlling what values are legal for your object. Therefore, once=
=20
> you have a constructor, the type isn't an aggregate anymore.
>
> And if you don't have a constructor for `C1`, why are its members private=
?=20
> What are you doing with classes with private members that have no=20
> constructors?
>
--=20
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 e=
mail 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/4160b2a5-4c71-4a49-9c04-c39df6782fa3%40isocpp.or=
g.
------=_Part_733_378975435.1515716448332
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Thursday, 11 January 2018 16:17:48 UTC, Nicol B=
olas 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"><=
br><br>On Thursday, January 11, 2018 at 9:59:43 AM UTC-5, Oleksandr Pikozh =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex">Maybe I am missing something.
<br>
<br>But from purely intuitive point of view, if this works=E2=80=A6
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1 i{1, =
2}; ///<--here
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>
<br>=E2=80=A6then these should also work:
<br>
<br>* Example 1 "aggregate-initializing private members within the cla=
ss=20
<br>definition":
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C1 {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 private:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C1 i{1, =
2}; ///<--here
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>
<br>* Example 2 "aggregate-initializing private members from a friend =
class":
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C2 {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 friend C2H;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 private:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C2H {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C2 i{1, =
2}; ///<--here
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>=C2=A0=C2=A0=C2=A0=C2=A0 }
<br>
<br>* Example 3 "aggregate-initializing protected members from a desce=
ndant=20
<br>class":
<br>
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C3 {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 protected:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 int f1, f2;
<br>=C2=A0=C2=A0=C2=A0=C2=A0 };
<br>=C2=A0=C2=A0=C2=A0=C2=A0 class C3D: public C3 {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 public:
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 static void s() {
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 C3 i{1, =
2}; ///<--here
<br>=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
<br>=C2=A0=C2=A0=C2=A0=C2=A0 }
<br>
<br>I.e. it is reasonable that aggregate initialization cannot be performed=
=20
<br>when it tries to affect unaccessible fields. And it is also reasonable=
=20
<br>that aggregate initialization cannot be performed even when at least on=
e=20
<br>of the class fields is unaccessible. But why aggregate initialization i=
s=20
<br>blocked for classes whose all fields are accessible from the current=20
<br>scope, I don't understand.<br></blockquote><div><br></div><div>Ther=
e is no technical reason why it has to be this way (though the recent `is_a=
ggregate` trait would be made non-useful). But it's still not a good id=
ea.</div><div><br></div><div>First, the ordering of members in different ac=
cess classes is undefined. So you would only be able to expand this to clas=
ses where NSDMs are all of the same access classes.</div></div></blockquote=
><div><br></div><div>I don't see that the layout in-memory of a mixed-a=
ccess class is relevant. The logical ordering of members as observed by the=
sequence in which NSDMs are constructed and (in reverse) destructed is sti=
ll the same as the overall lexical order of members within the class defini=
tion. Anyone who has the poor taste to write a class with mixed-access NSDM=
s is unlikely to expect the aggregate construction order to follow in-memor=
y order over lexical and runtime sequential order.</div><div>=C2=A0</div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></div><div=
>Second, this wouldn't work in real code.</div><div><br></div><div>Cons=
ider `C3`. Why are its members private?</div><div><br></div><div>If you wan=
ted a type that could hold any two integers, but you couldn't change th=
em once set, you would just declare them `const` and leave them public. But=
you made them mutable. And private.</div><div><br></div><div>Therefore, we=
must assume that you want to control the values of these two integers. To =
do that, you need to have a user-provided constructor. And once you have th=
at, the type isn't an aggregate anymore.</div><div><br></div><div>See, =
the word "aggregate" was not chosen arbitrarily. The concept of &=
quot;aggregate" is exactly <a href=3D"http://www.dictionary.com/browse=
/aggregate" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D&=
#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.dictionary.com%2Fbrowse=
%2Faggregate\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEH3WKo392YfXyomamMxKS1=
j1m9_Q';return true;" onclick=3D"this.href=3D'http://www.google.com=
/url?q\x3dhttp%3A%2F%2Fwww.dictionary.com%2Fbrowse%2Faggregate\x26sa\x3dD\x=
26sntz\x3d1\x26usg\x3dAFQjCNEH3WKo392YfXyomamMxKS1j1m9_Q';return true;"=
>what the word means</a>: a thing made entirely of other things. An aggrega=
te currently is an assemblage of objects, each of which can have any partic=
ular value which that subobject can store.</div><div><br></div><div>If you =
have a user-provided constructor, then the type isn't a mere aggregatio=
n of things. Its member subobjects cannot assume any value; you're cont=
rolling what values are legal for your object. Therefore, once you have a c=
onstructor, the type isn't an aggregate anymore.</div><div><br></div><d=
iv>And if you don't have a constructor for `C1`, why are its members pr=
ivate? What are you doing with classes with private members that have no co=
nstructors?</div></div></blockquote></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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/4160b2a5-4c71-4a49-9c04-c39df6782fa3%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/4160b2a5-4c71-4a49-9c04-c39df6782fa3=
%40isocpp.org</a>.<br />
------=_Part_733_378975435.1515716448332--
------=_Part_732_1303810768.1515716448332--
.