Topic: [std-proposals] Re: Adding the Keyword proxy i


Author: Jakob Riedle <jakob.riedle@gmail.com>
Date: Wed, 10 May 2017 05:10:35 -0700 (PDT)
Raw View
------=_Part_3821_1354060636.1494418235193
Content-Type: multipart/alternative;
 boundary="----=_Part_3822_947096536.1494418235194"

------=_Part_3822_947096536.1494418235194
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable



Am Mittwoch, 10. Mai 2017 12:46:22 UTC+2 schrieb Mingxin Wang:
>
>
>    - Changing the keyword =E2=80=9Cinterface=E2=80=9D into =E2=80=9Cproxy=
=E2=80=9D (*thanks to Thiago=20
>    Macierira, Myriachan and Jakob Riedle*), and
>   =20
> I did not vote for this :)
My opinion on this is still what Barry Revzin said:

> There's no reason to have both. They are the same thing. With Concepts TS=
,=20
> it's just a constraint placed on types for function templates and class=
=20
> templates. What we're talking about here is more runtime polymorphism - b=
ut=20
> the interface we're defining is exactly the same thing. We don't need two=
=20
> keywords with two sets of rules.


To give a little history of what *proxies/**interfaces *are, I quote Bjarne=
=20
[A History of C++: 1979=E2=88=921991]*:*

For many people, the largest single problem using C++ is the lack of an=20
> extensive standard
> library. A major problem in producing such a library is that C++ does not=
=20
> provide a sufficiently
> general facility for defining =E2=80=98=E2=80=98container classes=E2=80=
=99=E2=80=99 such as lists,=20
> vectors, and associative
> arrays.
> There are two approaches for providing such classes/types: One can either=
=20
> rely on dynamic typing
> and inheritance like Smalltalk does, or one can rely on static typing and=
=20
> a facility for arguments
> of type type. The former is very flexible, but carries a high runtime=20
> cost, and more importantly
> defies attempts to use static type checking to catch interface errors.=20
> Therefore, the latter approach
> was chosen.=20


Parameterization as It is in C++ is just one possible approach. *Both=20
Polymorphism and Parameterization have their drawbacks and their=20
advantages.*
C++ has just not (yet) explored the principle of dynamic generic=20
programming in the form of polymorphism.
For clarification and for sake of argument, that it is important and well=
=20
thought to fill this gap, I created the following diagram:

<https://lh3.googleusercontent.com/-sJPmuVztagk/WRL6x-6aI3I/AAAAAAAAAMs/DZF=
c5tBMJS8Gc0hXyquO0DZnM9bSfPYSwCLcB/s1600/Graphic.jpg>
Lets go ahead with what you said:=20

>
>    - Changing the way of passing the concrete implementations by value=20
>    into by reference, so that polymorphism and lifetime management are=20
>    decoupled (*thanks to Bengt Gustafsson*).
>
>
I replied to this topic, that it would be important, If we want to treat=20
dynamic concepts identically to static concepts, that they behave=20
identically to values of the concrete type:

std::function<void()> f1 =3D /**/;
> std::function<void()> f2();
>
> const std::function<void()> f3 =3D /**/;
> Callable<void()> c1 =3D f1; // This copies f1. Internally, an lvalue obje=
ct=20
> of type std::function<void()> is held.
> Callable<void()>& c2 =3D f1; // This references f1. Internally, an lvalue=
=20
> reference (std::function<void()>&) is stored.
> Callable<void()>&& c3 =3D f2(); // Internally stored as '
> std::function<void()>&&'.
> Callable<void()> c4 =3D f2(); // This moves the result of f2 into c4.=20
> Internally stored as real std::function<void()> lvalue .
> const Callable<void()>& c4 =3D f3; //Internally 'const &' as handle.
> // and so on...
>

Again, my answer assumed, that "proxies" or "interfaces" just introduce a=
=20
lot of redundancy to concepts
and therefore tries to come up with a solution that *reuses the concepts we=
=20
already have.*
*I hope this does not sound to rude Mingxing Wang, I'm trying to be=20
pragmatic.*

IMHO I don't think it is important at this point to discuss about a=20
*specific* Implementation yet.
As you have read in the quote from Bjarne, Polymorphism as Solution for=20
Generic Programming has been considered to be feasible :-)
However what I think is important to do right now is two things:

   1. Come up with an elegant SYNTAX:
      I think here it is important to not reinvent the wheel of concepts at=
=20
   runtime but rather *expand* concepts to runtime.
   2. Come up with an appropriate SEMANTICS (incl. Ownership management):=
=20
      Here I think we can either have a *different *rule set compared to=20
   how concepts names are used right now (as a placeholder for the real typ=
e)
      or rather adopt this syntax for runtime polymorphism. The latter=20
   would BTW mean to defer ownership management outside of the concept!
      (Using ref/const etc. qualifiers *around *the concept name).

Either way, we have to be clear what we are doing and why we are doing it.

Yours,
Jakob

PS: Independently of what I said above, I think the meat of the topic you=
=20
brought
up is very important and I find it really good that you're pursuing it!

--=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/5f6a0f96-8424-4853-9c09-3607db9f6443%40isocpp.or=
g.

------=_Part_3822_947096536.1494418235194
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>Am Mittwoch, 10. Mai 2017 12:46:22 UTC+2 schrieb M=
ingxin Wang:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><=
div><div><ul><li><font face=3D"georgia, serif">Changing the keyword =E2=80=
=9Cinterface=E2=80=9D into =E2=80=9Cproxy=E2=80=9D (<b>thanks to Thiago Mac=
ierira, Myriachan and Jakob Riedle</b>), and<br></font></li></ul></div></di=
v></div></blockquote><div>I did not vote for this :)</div><div>My opinion o=
n this is still what Barry Revzin said:</div><div><blockquote class=3D"gmai=
l_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204=
, 204, 204); padding-left: 1ex;">There&#39;s no reason to have both. They a=
re the same thing. With Concepts TS, it&#39;s just a constraint placed on t=
ypes for function templates and class templates. What we&#39;re talking abo=
ut here is more runtime polymorphism - but the interface we&#39;re defining=
 is exactly the same thing. We don&#39;t need two keywords with two sets of=
 rules.</blockquote><br></div><div>To give a little history of what <i>prox=
ies/</i><i>interfaces </i>are, I quote Bjarne [A History of C++: 1979=E2=88=
=921991]<i>:</i></div><div><br></div><blockquote class=3D"gmail_quote" styl=
e=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); =
padding-left: 1ex;">For many people, the largest single problem using C++ i=
s the lack of an extensive standard<br>library. A major problem in producin=
g such a library is that C++ does not provide a sufficiently<br>general fac=
ility for defining =E2=80=98=E2=80=98container classes=E2=80=99=E2=80=99 su=
ch as lists, vectors, and associative<br>arrays.<br>There are two approache=
s for providing such classes/types: One can either rely on dynamic typing<b=
r>and inheritance like Smalltalk does, or one can rely on static typing and=
 a facility for arguments<br>of type <font face=3D"courier new, monospace">=
type</font>. The former is very flexible, but carries a high runtime cost, =
and more importantly<br>defies attempts to use static type checking to catc=
h interface errors. Therefore, the latter approach<br>was chosen.=C2=A0</bl=
ockquote><div><br></div><div>Parameterization as It is in C++ is just one p=
ossible approach. <b>Both Polymorphism and Parameterization have their draw=
backs and their advantages.</b></div><div>C++ has just not (yet) explored t=
he principle of dynamic generic programming in the form of polymorphism.</d=
iv><div>For clarification and for sake of argument, that it is important an=
d well thought to fill this gap, I created the following diagram:</div><div=
><br></div><p class=3D"separator" style=3D"text-align: center; clear: both;=
"><a imageanchor=3D"1" href=3D"https://lh3.googleusercontent.com/-sJPmuVzta=
gk/WRL6x-6aI3I/AAAAAAAAAMs/DZFc5tBMJS8Gc0hXyquO0DZnM9bSfPYSwCLcB/s1600/Grap=
hic.jpg" style=3D"margin-left: 1em; margin-right: 1em;"><img src=3D"https:/=
/lh3.googleusercontent.com/-sJPmuVztagk/WRL6x-6aI3I/AAAAAAAAAMs/DZFc5tBMJS8=
Gc0hXyquO0DZnM9bSfPYSwCLcB/s320/Graphic.jpg" border=3D"0" width=3D"320" hei=
ght=3D"176"></a></p><div>Lets go ahead with what you said:=C2=A0</div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div><ul><li>=
<font face=3D"georgia, serif">Changing the way of passing the concrete impl=
ementations by value into by reference, so that polymorphism and lifetime m=
anagement are decoupled (<b>thanks to Bengt Gustafsson</b>).</font></li></u=
l></div></div></div></blockquote><div><br></div><div>I replied to this topi=
c, that it would be important, If we want to treat dynamic concepts identic=
ally to static concepts, that they behave identically to values of the conc=
rete type:</div><div><br></div><blockquote class=3D"gmail_quote" style=3D"m=
argin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); paddin=
g-left: 1ex;"><div class=3D"prettyprint" style=3D"background-color: rgb(250=
, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-=
width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">function</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">void</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">()&gt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> f1 </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" clas=
s=3D"styled-by-prettify">/**/</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br>std</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">::</span><span style=3D"color: #008;" class=3D"styled-by-prettify">f=
unction</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt=
;</span><span style=3D"color: #008;" class=3D"styled-by-prettify">void</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">()&gt;</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> f2</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">();</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">const</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">::</span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">function</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"styled-=
by-prettify">void</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">()&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> f3 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #800;" class=3D"styled-by-prettify">/**/</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #=
606;" class=3D"styled-by-prettify">Callable</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">void</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">()&gt;</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> c1 </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> f1</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #800;" class=3D"styled-by-prettify">// This copies f1. In=
ternally, an lvalue object of type std::function&lt;void()&gt; is held.</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><sp=
an style=3D"color: #606;" class=3D"styled-by-prettify">Callable</span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">void</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">()&gt;&amp;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> c2 </span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> f1</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pret=
tify">// This references f1. Internally, an lvalue reference (std::function=
&lt;void()&gt;&amp;) is stored.</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br></span><span style=3D"color: #606;" class=3D"style=
d-by-prettify">Callable</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">void</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>()&gt;&amp;&amp;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> c3 </span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> f2</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">();</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #800;" class=3D"styled-by-prettify">// Internally stored as &#39=
;</span><span style=3D"color: rgb(136, 0, 0); font-family: Arial, Helvetica=
, sans-serif;">std::function&lt;void()&gt;</span><span style=3D"color: rgb(=
136, 0, 0); font-family: Arial, Helvetica, sans-serif;">&amp;&amp;&#39;.</s=
pan></div><div class=3D"subprettyprint"><span style=3D"color: #606;" class=
=3D"styled-by-prettify">Callable</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">void</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">()&gt;</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> c4 </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> f2</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">();</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #800;" class=3D"styled-by-prettify">// This moves the result of =
f2 into c4. Internally stored as real=C2=A0</span><span style=3D"color: rgb=
(136, 0, 0); font-family: Arial, Helvetica, sans-serif;">std::function&lt;v=
oid()&gt;=C2=A0</span><span class=3D"styled-by-prettify" style=3D"font-fami=
ly: Arial, Helvetica, sans-serif; color: rgb(136, 0, 0);">lvalue </span><sp=
an class=3D"styled-by-prettify" style=3D"font-family: Arial, Helvetica, san=
s-serif; color: rgb(136, 0, 0);">.</span></div><div class=3D"subprettyprint=
"><span style=3D"color: #008;" class=3D"styled-by-prettify">const</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">Callable</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">void</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">()&gt;&amp;</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> c4 </span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> f3</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify">/=
/Internally &#39;const &amp;&#39; as handle.</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #800;" c=
lass=3D"styled-by-prettify">// and so on...</span></div></code></div></bloc=
kquote><div><br></div><div>Again, my answer assumed, that &quot;proxies&quo=
t; or &quot;interfaces&quot; just introduce a lot of redundancy to concepts=
</div><div>and therefore tries to come up with a solution that <b>reuses th=
e concepts we already have.</b></div><div><b>I hope this does not sound to =
rude Mingxing Wang, I&#39;m trying to be pragmatic.</b></div><div><br></div=
><div>IMHO I don&#39;t think it is important at this point to discuss about=
 a <i>specific</i> Implementation yet.</div><div>As you have read in the qu=
ote from Bjarne, Polymorphism as Solution for Generic Programming has been =
considered to be feasible :-)<br></div><div>However what I think is importa=
nt to do right now is two things:</div><div><ol><li>Come up with an elegant=
 SYNTAX:<br>=C2=A0 =C2=A0I think here it is important to not reinvent the w=
heel of concepts at runtime but rather <b>expand</b> concepts to runtime.</=
li><li>Come up with an appropriate SEMANTICS (incl. Ownership management):=
=C2=A0<br>=C2=A0 =C2=A0Here I think we can either have a <b>different </b>r=
ule set compared to how concepts names are used right now (as a placeholder=
 for the real type)<br>=C2=A0 =C2=A0or rather adopt this syntax for runtime=
 polymorphism. The latter would BTW mean to defer ownership management outs=
ide of the concept!<br>=C2=A0 =C2=A0(Using ref/const etc. qualifiers <b>aro=
und </b>the concept name).</li></ol>Either way, we have to be clear what we=
 are doing and why we are doing it.</div><div><br></div><div>Yours,</div><d=
iv>Jakob</div><div><br></div><div>PS: Independently of what I said above, I=
 think the meat of the topic you brought</div><div>up is very important and=
 I find it really good that you&#39;re pursuing it!</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/5f6a0f96-8424-4853-9c09-3607db9f6443%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/5f6a0f96-8424-4853-9c09-3607db9f6443=
%40isocpp.org</a>.<br />

------=_Part_3822_947096536.1494418235194--

------=_Part_3821_1354060636.1494418235193--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 10 May 2017 08:06:45 -0700 (PDT)
Raw View
------=_Part_4013_2120837292.1494428805470
Content-Type: multipart/alternative;
 boundary="----=_Part_4014_1495847048.1494428805471"

------=_Part_4014_1495847048.1494428805471
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Wednesday, May 10, 2017 at 6:46:22 AM UTC-4, Mingxin Wang wrote:
>
> This is an update version for another topic =E2=80=9CAdding the Keyword=
=20
> =E2=80=9Cinterface=E2=80=9D in C++=20
> <https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/uyfpe=
yEyW4o>
> =E2=80=9D
>

First, there's no need to create a new thread because you changed the name=
=20
of the keyword. There was still an active discussion going on in the old=20
thread.

Second, the keyword itself is essentially irrelevant. Your feature is not=
=20
about adding a keyword to C++; it's about adding automatic type erasure=20
generation based on a "concept" of some form. What keyword you use to=20
invoke this does not matter. So you shouldn't title the thread "Adding=20
keyword X to C++"; it should be titled based on what the actual feature is.

Third, as for the feature, it's still weak. It would be much better to base=
=20
it on a concept. It's a much better mechanism for specifying this sort of=
=20
thing.

--=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/0f7b92a7-2318-4786-b617-b1fcc6cf0c2c%40isocpp.or=
g.

------=_Part_4014_1495847048.1494428805471
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, May 10, 2017 at 6:46:22 AM UTC-4, Mingxin Wa=
ng 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"><fon=
t face=3D"georgia, serif">This is an update version for another topic =E2=
=80=9C<a href=3D"https://groups.google.com/a/isocpp.org/forum/#!topic/std-p=
roposals/uyfpeyEyW4o" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"thi=
s.href=3D&#39;https://groups.google.com/a/isocpp.org/forum/#!topic/std-prop=
osals/uyfpeyEyW4o&#39;;return true;" onclick=3D"this.href=3D&#39;https://gr=
oups.google.com/a/isocpp.org/forum/#!topic/std-proposals/uyfpeyEyW4o&#39;;r=
eturn true;">Adding the Keyword =E2=80=9Cinterface=E2=80=9D in C++</a>=E2=
=80=9D</font></div></blockquote><div><br>First, there&#39;s no need to crea=
te a new thread because you changed the name of the keyword. There was stil=
l an active discussion going on in the old thread.<br><br>Second, the keywo=
rd itself is essentially irrelevant. Your feature is not about adding a key=
word to C++; it&#39;s about adding automatic type erasure generation based =
on a &quot;concept&quot; of some form. What keyword you use to invoke this =
does not matter. So you shouldn&#39;t title the thread &quot;Adding keyword=
 X to C++&quot;; it should be titled based on what the actual feature is.<b=
r><br>Third, as for the feature, it&#39;s still weak. It would be much bett=
er to base it on a concept. It&#39;s a much better mechanism for specifying=
 this sort of thing.<br></div></div>

<p></p>

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

------=_Part_4014_1495847048.1494428805471--

------=_Part_4013_2120837292.1494428805470--

.


Author: Mingxin Wang <wmx16835vv@163.com>
Date: Wed, 10 May 2017 10:14:00 -0700 (PDT)
Raw View
------=_Part_4272_35259288.1494436440349
Content-Type: multipart/alternative;
 boundary="----=_Part_4273_623672606.1494436440350"

------=_Part_4273_623672606.1494436440350
Content-Type: text/plain; charset="UTF-8"


>
> I replied to this topic, that it would be important, If we want to treat
> dynamic concepts identically to static concepts, that they behave
> identically to values of the concrete type:
>
Again, my answer assumed, that "proxies" or "interfaces" just introduce a
> lot of redundancy to concepts

and therefore tries to come up with a solution that *reuses the concepts we
> already have.*


As I said before, the "proxies" is a use case to the "concepts", and is not
a runtime alternative, because of, from my point of view, two reasons:

*The first reason is: There is little overlap between the scenarios for
using the two mechanisms.*

The "concepts" is usually used when calling a function template (or storing
in a class template independently) to ensure the input types to be
well-formed. The "proxies" can be used when it is required to store
different implementations with a uniform format.

For example, the "Lockable requirements" is defined in C++ standard as:

<https://lh3.googleusercontent.com/-MvjB8whRerw/WRM4pJW4CYI/AAAAAAAAAEI/njRc6Jxq6kIWuU-AfCtt6lrYB0FeMRTPwCLcB/s1600/Untitled.png>


This term is required in many library functions, e.g., "std::lock" and
"std::try_lock":

<https://lh3.googleusercontent.com/-DUEvGKmLi0k/WRM4VVFxPzI/AAAAAAAAAEE/Ec0ADOrUL00Tf5y37zzbe4GW3yOj4onIgCLcB/s1600/Untitled.png>


The "concepts" can be used for these functions, but the mutexes are not
required to be stored with a uniform format. Thus it requires the
"concepts" rather than the "proxies" here.

There is another example I posted earlier that requires the "proxies"
rather than the "concepts":

For example, suppose we want to store some iterators (may have different
> types) in a container and perform some operations with them (only
> "operator*", "operator++" and "operator==" are used), we may write the
> following code with "interfaces":

template <class T>
> *proxy* It {
>   T operator*();
>   void operator++(); // The returned value is not required
>   bool operator==(const It&);
> };
>
> std::vector<It<int>> vec;
>
> for (It<int> it : vec) { ... }
>

What if we build another wrapper type that implements everything specified
in the "ranges TS"? Let's see what is defined in
"std::experimental::ranges::Iterator" first:

template <class I>
concept bool Iterator() {
    return ranges::WeaklyIncrementable<I>()
        && requires(I i) {
               { *i } -> auto&&; // Requires: i is dereferenceable
           };
}

So, what is "ranges::WeaklyIncrementable<I>"? It is defined as follows:

concept bool WeaklyIncrementable() {
    return ranges::Semiregular<I>()
        && requires(I i) {
               typename ranges::difference_type_t<I>;
               requires
ranges::SignedIntegral<ranges::difference_type_t<I>>();
               { ++i } -> ranges::Same<I&>; /* not required to be equality
preserving */
               i++; /* not required to be equality preserving */
           };
}

It depends on another concept again! So what exactly does concept
"std::experimental::ranges::Iterator" defines?

template <class T>
concept bool Destructible() {
    return requires(T t, const T ct, T* p) {
               { t.T() } noexcept;
               { &t }  -> ranges::Same<T*>; /* not required to be equality
preserving */
               { &ct } -> ranges::Same<const T*>; /* not required to be
equality preserving */
               delete p;
               delete[] p;
           };
}

template < class T, class... Args >
concept bool __ConstructibleObject =  /* exposition only */
    ranges::Destructible<T>() && requires(Args&&... args) {
       T{ std::forward<Args>(args)... };
       new T{ std::forward<Args>(args)... };
    };

template < class T, class... Args >
concept bool __BindableReference = /* exposition only */
    std::is_reference<T>::value && requires(Args&&... args) {
       T( std::forward<Args>(args)... );
    };

template < class T, class... Args >
concept bool Constructible() {
    return __ConstructibleObject<T, Args...> || __BindableReference<T,
Args...>;
}

template < class T, class U >
concept bool ConvertibleTo() { return std::is_convertible<T, U>::value; }

template <class T>
concept bool MoveConstructible() {
    return ranges::Constructible<T, std::remove_cv_t<T>&&>() &&
           ranges::ConvertibleTo<std::remove_cv_t<T>&&, T>();
}

template <class T>
concept bool CopyConstructible() {
    return ranges::MoveConstructible<T>() &&
           ranges::Constructible<T, const std::remove_cv_t<T>&>() &&
           ranges::ConvertibleTo<std::remove_cv_t<T>&, T>() &&
           ranges::ConvertibleTo<const std::remove_cv_t<T>&, T>() &&
           ranges::ConvertibleTo<const std::remove_cv_t<T>&&, T>();
}

template < class T, class U >
concept bool CommonReference() {
    return requires(T (&t)(), U (&u)()) {
        typename std::common_reference_t<T, U>;
        typename std::common_reference_t<U, T>;
        requires ranges::Same<std::common_reference_t<T, U>,
                              std::common_reference_t<U, T>>();
        std::common_reference_t<T, U>(t());
        std::common_reference_t<T, U>(u());
    };
}

template <class T, class U>
concept bool Assignable() {
    return ranges::CommonReference<const T&, const U&>() &&
           requires(T&& t, U&& u) {
               { std::forward<T>(t) = std::forward<U>(u) } ->
ranges::Same<T&>;
           };
}

template <class T>
concept bool Swappable() {
    return requires(T&& a, T&& b) {
               ranges::swap(std::forward<T>(a), std::forward<T>(b));
           };
}

template <class T, class U>
concept bool Swappable() {
    return ranges::Swappable<T>() &&
           ranges::Swappable<U>() &&
           ranges::CommonReference<const T&, const U&>() &&
           requires(T&& t, U&& u) {
               ranges::swap(std::forward<T>(t), std::forward<U>(u));
               ranges::swap(std::forward<U>(u), std::forward<T>(t));
           };
}

template <class T>
concept bool Movable() {
    return ranges::MoveConstructible<T>() &&
           ranges::Assignable<T&, T>() &&
           ranges::Swappable<T&>();
}

template <class T>
concept bool Copyable() {
    return ranges::CopyConstructible<T>() &&
           ranges::Movable<T>() &&
           ranges::Assignable<T&, const T&>();
}

template <class T>
concept bool DefaultConstructible() {
    return ranges::Constructible<T>() &&
           requires(const std::size_t n) {
               new T[n]{}; /* not required to be equality preserving */
           };
}

template <class T>
concept bool Semiregular() {
    return ranges::Copyable<T>() &&
           ranges::DefaultConstructible<T>();
}

template < class T >
concept bool Integral() { return std::is_integral<T>::value; }

template < class T >
concept bool SignedIntegral() { return Integral<T>() &&
std::is_signed<T>::value; }

template <class I>
concept bool WeaklyIncrementable() {
    return ranges::Semiregular<I>()
        && requires(I i) {
               typename ranges::difference_type_t<I>;
               requires
ranges::SignedIntegral<ranges::difference_type_t<I>>();
               { ++i } -> ranges::Same<I&>; /* not required to be equality
preserving */
               i++; /* not required to be equality preserving */
           };
}

template <class I>
concept bool Iterator() {
    return ranges::WeaklyIncrementable<I>()
        && requires(I i) {
               { *i } -> auto&&; // Requires: i is dereferenceable
           };
}

A type satisfies "concept template Iterator" if and only if all the
concepts above are satisfied! Shall we turn these stuff into a runtime
wrapper? I suppose not, because that will introduce much runtime overhead,
and I prefer to define a proxy instead. After all, only 3 member functions
is required to be abstract at runtime.

*The second reason is: Some concepts are difficult to turn into specific
type requirements so far.*

It is true that we can turn some simple concepts into proxies. For example:

template <class T>
concept bool Foo() {
  return requires(T t) {
    { t() };
    { t.f() } -> int;
  }
}

proxy Foo {
  void operator()();
  int f();
}

But it is incredibly difficault for some other concepts. For example:

template <class T>
concept bool Foo() {
  return requires(T t1, T t2, const T t3) {
    t1.op_0(t2.op_1(t3.op_2()));
  };
}

It is easy to check whether the expressions are well-formed at compile-time
for a concrete type T. But how can we abstract such type at runtime?

Mingxin Wang

--
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/78f335a4-a099-429d-bcd2-8fe3a9b185c1%40isocpp.org.

------=_Part_4273_623672606.1494436440350
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px=
 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-c=
olor: rgb(204, 204, 204); padding-left: 1ex;">I replied to this topic, that=
 it would be important, If we want to treat dynamic concepts identically to=
 static concepts, that they behave identically to values of the concrete ty=
pe:<br></blockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0px =
0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-lef=
t-color: rgb(204, 204, 204); padding-left: 1ex;">Again, my answer assumed, =
that &quot;proxies&quot; or &quot;interfaces&quot; just introduce a lot of =
redundancy to concepts</blockquote><blockquote class=3D"gmail_quote" style=
=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: s=
olid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;">and theref=
ore tries to come up with a solution that=C2=A0<b>reuses the concepts we al=
ready have.</b>=C2=A0</blockquote><div><br></div><div><font face=3D"georgia=
, serif">As I said before, the &quot;proxies&quot; is a use case to the &qu=
ot;concepts&quot;, and is not a runtime alternative, because of, from my po=
int of view, two reasons:</font></div><div><font face=3D"georgia, serif"><b=
r></font></div><div><font size=3D"4" face=3D"georgia, serif"><b>The first r=
eason is: There is little overlap between the scenarios for using the two m=
echanisms.</b></font></div><div><font face=3D"georgia, serif"><br></font></=
div><div><font face=3D"georgia, serif">The &quot;concepts&quot; is usually =
used when calling a function template (or storing in a class template=C2=A0=
independently) to ensure the input types to be well-formed. The &quot;proxi=
es&quot; can be used when it is required to store different implementations=
 with a=C2=A0uniform format.</font></div><div><font face=3D"georgia, serif"=
><br></font></div><div><font face=3D"georgia, serif">For example, the &quot=
;Lockable requirements&quot; is defined in C++ standard as:</font></div><p =
class=3D"separator" style=3D"text-align: center; clear: both;"><a imageanch=
or=3D"1" href=3D"https://lh3.googleusercontent.com/-MvjB8whRerw/WRM4pJW4CYI=
/AAAAAAAAAEI/njRc6Jxq6kIWuU-AfCtt6lrYB0FeMRTPwCLcB/s1600/Untitled.png" styl=
e=3D"margin-left: 1em; margin-right: 1em;"><img src=3D"https://lh3.googleus=
ercontent.com/-MvjB8whRerw/WRM4pJW4CYI/AAAAAAAAAEI/njRc6Jxq6kIWuU-AfCtt6lrY=
B0FeMRTPwCLcB/s400/Untitled.png" border=3D"0" width=3D"400" height=3D"231">=
</a></p><p class=3D"separator" style=3D"text-align: center; clear: both;"><=
br></p><div><font face=3D"georgia, serif">This term is required in many lib=
rary functions, e.g., &quot;std::lock&quot; and &quot;std::try_lock&quot;:<=
/font></div><div><br></div><p class=3D"separator" style=3D"text-align: cent=
er; clear: both;"><a imageanchor=3D"1" href=3D"https://lh3.googleuserconten=
t.com/-DUEvGKmLi0k/WRM4VVFxPzI/AAAAAAAAAEE/Ec0ADOrUL00Tf5y37zzbe4GW3yOj4onI=
gCLcB/s1600/Untitled.png" style=3D"margin-left: 1em; margin-right: 1em;"><i=
mg src=3D"https://lh3.googleusercontent.com/-DUEvGKmLi0k/WRM4VVFxPzI/AAAAAA=
AAAEE/Ec0ADOrUL00Tf5y37zzbe4GW3yOj4onIgCLcB/s400/Untitled.png" border=3D"0"=
 width=3D"400" height=3D"230"></a></p><p class=3D"separator" style=3D"text-=
align: center; clear: both;"><br></p><div><font face=3D"georgia, serif">The=
 &quot;concepts&quot; can be used for these functions, but the mutexes are =
not required to be stored with a uniform format. Thus it requires the &quot=
;concepts&quot; rather than the &quot;proxies&quot; here.</font></div><div>=
<font face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, =
serif">There is another example I posted earlier that requires the &quot;pr=
oxies&quot; rather than the &quot;concepts&quot;:</font></div><div><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; bor=
der-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, =
204, 204); padding-left: 1ex;"><span style=3D"font-family: georgia, serif;"=
>For example, suppose we want to store some iterators (may have different t=
ypes) in a container and perform some operations with them (only &quot;oper=
ator*&quot;, &quot;operator++&quot; and &quot;operator=3D=3D&quot; are used=
), we may write the following code with &quot;interfaces&quot;:</span></blo=
ckquote><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8e=
x; border-left-width: 1px; border-left-style: solid; border-left-color: rgb=
(204, 204, 204); padding-left: 1ex;"><div class=3D"prettyprint" style=3D"bo=
rder: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-color=
: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><font color=3D"#660066"><div class=3D"subprettyprint"><span style=3D"=
font-family: Arial, Helvetica, sans-serif;">template &lt;class T&gt;</span>=
<br></div><div class=3D"subprettyprint"><b>proxy</b> It {</div><div class=
=3D"subprettyprint">=C2=A0 T operator*();</div><div class=3D"subprettyprint=
">=C2=A0 void operator++(); // The returned value is not required</div><div=
 class=3D"subprettyprint">=C2=A0 bool operator=3D=3D(const It&amp;);</div><=
div class=3D"subprettyprint">};</div><div class=3D"subprettyprint"><br></di=
v><div class=3D"subprettyprint">std::vector&lt;It&lt;int&gt;&gt; vec;</div>=
<div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">for (=
It&lt;int&gt; it : vec) { ... }</div></font></div></code></div></blockquote=
><div><br></div><div>What if we build another wrapper type that implements =
everything specified in the &quot;ranges TS&quot;? Let&#39;s see what is de=
fined in &quot;std::experimental::ranges::Iterator&quot; first:</div><div><=
br></div><div><div class=3D"prettyprint" style=3D"border: 1px solid rgb(187=
, 187, 187); word-wrap: break-word; background-color: rgb(250, 250, 250);">=
<code class=3D"prettyprint"><div class=3D"subprettyprint"><div class=3D"sub=
prettyprint">template &lt;class I&gt;</div><div class=3D"subprettyprint">co=
ncept bool Iterator() {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 re=
turn ranges::WeaklyIncrementable&lt;I&gt;()</div><div class=3D"subprettypri=
nt">=C2=A0 =C2=A0 =C2=A0 =C2=A0 &amp;&amp; requires(I i) {</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
{ *i } -&gt; auto&amp;&amp;; // Requires: i is dereferenceable</div><div cl=
ass=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0};</div><di=
v class=3D"subprettyprint">}</div></div></code></div><br><font face=3D"geor=
gia, serif">So, what is &quot;ranges::WeaklyIncrementable&lt;I&gt;&quot;? I=
t is defined as follows:</font></div><div><br></div><div><div class=3D"pret=
typrint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-wo=
rd; background-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div=
 class=3D"subprettyprint"><div class=3D"subprettyprint">concept bool Weakly=
Incrementable() {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return r=
anges::Semiregular&lt;I&gt;()</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 &amp;&amp; requires(I i) {</div><div class=3D"subprettypr=
int">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0typename ranges=
::difference_type_t&lt;I&gt;;</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0requires ranges::SignedIntegra=
l&lt;ranges::difference_type_t&lt;I&gt;&gt;();</div><div class=3D"subpretty=
print">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ ++i } -&gt;=
 ranges::Same&lt;I&amp;&gt;; /* not required to be equality preserving */</=
div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0i++; /* not required to be equality preserving */</div><div c=
lass=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0};</div><d=
iv class=3D"subprettyprint">}</div></div></code></div><br><font face=3D"geo=
rgia, serif">It depends on another concept again! So what exactly does conc=
ept &quot;std::experimental::ranges::Iterator&quot; defines?</font></div><d=
iv><br></div><div><div class=3D"prettyprint" style=3D"border: 1px solid rgb=
(187, 187, 187); word-wrap: break-word; background-color: rgb(250, 250, 250=
);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><font color=
=3D"#660066"><div class=3D"subprettyprint">template &lt;class T&gt;</div><d=
iv class=3D"subprettyprint">concept bool Destructible() {</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 return requires(T t, const T ct, T* p) {<=
/div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0{ t.T() } noexcept;</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ &amp;t } =C2=A0-&gt; =
ranges::Same&lt;T*&gt;; /* not required to be equality preserving */</div><=
div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0{ &amp;ct } -&gt; ranges::Same&lt;const T*&gt;; /* not required t=
o be equality preserving */</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0delete p;</div><div class=3D"s=
ubprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0delet=
e[] p;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0};</div><div class=3D"subprettyprint">}</div><div class=3D"subpre=
ttyprint"><br></div><div class=3D"subprettyprint">template &lt; class T, cl=
ass... Args &gt;</div><div class=3D"subprettyprint">concept bool __Construc=
tibleObject =3D =C2=A0/* exposition only */</div><div class=3D"subprettypri=
nt">=C2=A0 =C2=A0 ranges::Destructible&lt;T&gt;() &amp;&amp; requires(Args&=
amp;&amp;... args) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=
=A0 =C2=A0T{ std::forward&lt;Args&gt;(args)... };</div><div class=3D"subpre=
ttyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0new T{ std::forward&lt;Args&gt;(args).=
... };</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 };</div><div class=
=3D"subprettyprint"><br></div><div class=3D"subprettyprint">template &lt; c=
lass T, class... Args &gt;</div><div class=3D"subprettyprint">concept bool =
__BindableReference =3D /* exposition only */</div><div class=3D"subprettyp=
rint">=C2=A0 =C2=A0 std::is_reference&lt;T&gt;::value &amp;&amp; requires(A=
rgs&amp;&amp;... args) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0T( std::forward&lt;Args&gt;(args)... );</div><div class=3D"sub=
prettyprint">=C2=A0 =C2=A0 };</div><div class=3D"subprettyprint"><br></div>=
<div class=3D"subprettyprint">template &lt; class T, class... Args &gt;</di=
v><div class=3D"subprettyprint">concept bool Constructible() {</div><div cl=
ass=3D"subprettyprint">=C2=A0 =C2=A0 return __ConstructibleObject&lt;T, Arg=
s...&gt; || __BindableReference&lt;T, Args...&gt;;</div><div class=3D"subpr=
ettyprint">}</div><div class=3D"subprettyprint"><br></div><div class=3D"sub=
prettyprint">template &lt; class T, class U &gt;</div><div class=3D"subpret=
typrint">concept bool ConvertibleTo() { return std::is_convertible&lt;T, U&=
gt;::value; }</div><div class=3D"subprettyprint"><br></div><div class=3D"su=
bprettyprint">template &lt;class T&gt;</div><div class=3D"subprettyprint">c=
oncept bool MoveConstructible() {</div><div class=3D"subprettyprint">=C2=A0=
 =C2=A0 return ranges::Constructible&lt;T, std::remove_cv_t&lt;T&gt;&amp;&a=
mp;&gt;() &amp;&amp;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0ranges::ConvertibleTo&lt;std::remove_cv_t&lt;T&gt;&=
amp;&amp;, T&gt;();</div><div class=3D"subprettyprint">}</div><div class=3D=
"subprettyprint"><br></div><div class=3D"subprettyprint">template &lt;class=
 T&gt;</div><div class=3D"subprettyprint">concept bool CopyConstructible() =
{</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return ranges::MoveConst=
ructible&lt;T&gt;() &amp;&amp;</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::Constructible&lt;T, const std::re=
move_cv_t&lt;T&gt;&amp;&gt;() &amp;&amp;</div><div class=3D"subprettyprint"=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::ConvertibleTo&lt;std::rem=
ove_cv_t&lt;T&gt;&amp;, T&gt;() &amp;&amp;</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::ConvertibleTo&lt;const =
std::remove_cv_t&lt;T&gt;&amp;, T&gt;() &amp;&amp;</div><div class=3D"subpr=
ettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::ConvertibleTo&l=
t;const std::remove_cv_t&lt;T&gt;&amp;&amp;, T&gt;();</div><div class=3D"su=
bprettyprint">}</div><div class=3D"subprettyprint"><br></div><div class=3D"=
subprettyprint">template &lt; class T, class U &gt;</div><div class=3D"subp=
rettyprint">concept bool CommonReference() {</div><div class=3D"subprettypr=
int">=C2=A0 =C2=A0 return requires(T (&amp;t)(), U (&amp;u)()) {</div><div =
class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 typename std::common_r=
eference_t&lt;T, U&gt;;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 typename std::common_reference_t&lt;U, T&gt;;</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 requires ranges::Same&lt;st=
d::common_reference_t&lt;T, U&gt;,</div><div class=3D"subprettyprint">=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 std::common_reference_t&lt;U, T&gt;&gt;();</div=
><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 std::common_refe=
rence_t&lt;T, U&gt;(t());</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 std::common_reference_t&lt;T, U&gt;(u());</div><div class=3D"=
subprettyprint">=C2=A0 =C2=A0 };</div><div class=3D"subprettyprint">}</div>=
<div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">templ=
ate &lt;class T, class U&gt;</div><div class=3D"subprettyprint">concept boo=
l Assignable() {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return ra=
nges::CommonReference&lt;const T&amp;, const U&amp;&gt;() &amp;&amp;</div><=
div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0requi=
res(T&amp;&amp; t, U&amp;&amp; u) {</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ std::forward&lt;T&gt;=
(t) =3D std::forward&lt;U&gt;(u) } -&gt; ranges::Same&lt;T&amp;&gt;;</div><=
div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0};</d=
iv><div class=3D"subprettyprint">}</div><div class=3D"subprettyprint"><br><=
/div><div class=3D"subprettyprint">template &lt;class T&gt;</div><div class=
=3D"subprettyprint">concept bool Swappable() {</div><div class=3D"subpretty=
print">=C2=A0 =C2=A0 return requires(T&amp;&amp; a, T&amp;&amp; b) {</div><=
div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0ranges::swap(std::forward&lt;T&gt;(a), std::forward&lt;T&gt;(b));=
</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0};</div><div class=3D"subprettyprint">}</div><div class=3D"subprettyprin=
t"><br></div><div class=3D"subprettyprint">template &lt;class T, class U&gt=
;</div><div class=3D"subprettyprint">concept bool Swappable() {</div><div c=
lass=3D"subprettyprint">=C2=A0 =C2=A0 return ranges::Swappable&lt;T&gt;() &=
amp;&amp;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0ranges::Swappable&lt;U&gt;() &amp;&amp;</div><div class=3D"sub=
prettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::CommonReferen=
ce&lt;const T&amp;, const U&amp;&gt;() &amp;&amp;</div><div class=3D"subpre=
ttyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0requires(T&amp;&amp; t, =
U&amp;&amp; u) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::swap(std::forward&lt;T&gt;(t), st=
d::forward&lt;U&gt;(u));</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::swap(std::forward&lt;U&gt;=
(u), std::forward&lt;T&gt;(t));</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0};</div><div class=3D"subprettyprint">}</=
div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">t=
emplate &lt;class T&gt;</div><div class=3D"subprettyprint">concept bool Mov=
able() {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return ranges::Mo=
veConstructible&lt;T&gt;() &amp;&amp;</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::Assignable&lt;T&amp;, T&gt=
;() &amp;&amp;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0ranges::Swappable&lt;T&amp;&gt;();</div><div class=3D"subp=
rettyprint">}</div><div class=3D"subprettyprint"><br></div><div class=3D"su=
bprettyprint">template &lt;class T&gt;</div><div class=3D"subprettyprint">c=
oncept bool Copyable() {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 r=
eturn ranges::CopyConstructible&lt;T&gt;() &amp;&amp;</div><div class=3D"su=
bprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::Movable&lt;T=
&gt;() &amp;&amp;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0ranges::Assignable&lt;T&amp;, const T&amp;&gt;();</div>=
<div class=3D"subprettyprint">}</div><div class=3D"subprettyprint"><br></di=
v><div class=3D"subprettyprint">template &lt;class T&gt;</div><div class=3D=
"subprettyprint">concept bool DefaultConstructible() {</div><div class=3D"s=
ubprettyprint">=C2=A0 =C2=A0 return ranges::Constructible&lt;T&gt;() &amp;&=
amp;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0requires(const std::size_t n) {</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0new T[n]{}; /* not r=
equired to be equality preserving */</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0};</div><div class=3D"subprettyprint"=
>}</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprin=
t">template &lt;class T&gt;</div><div class=3D"subprettyprint">concept bool=
 Semiregular() {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return ra=
nges::Copyable&lt;T&gt;() &amp;&amp;</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ranges::DefaultConstructible&lt;T&gt;=
();</div><div class=3D"subprettyprint">}</div><div class=3D"subprettyprint"=
><br></div><div class=3D"subprettyprint">template &lt; class T &gt;</div><d=
iv class=3D"subprettyprint">concept bool Integral() { return std::is_integr=
al&lt;T&gt;::value; }</div><div class=3D"subprettyprint"><br></div><div cla=
ss=3D"subprettyprint">template &lt; class T &gt;</div><div class=3D"subpret=
typrint">concept bool SignedIntegral() { return Integral&lt;T&gt;() &amp;&a=
mp; std::is_signed&lt;T&gt;::value; }</div><div class=3D"subprettyprint"><b=
r></div><div class=3D"subprettyprint">template &lt;class I&gt;</div><div cl=
ass=3D"subprettyprint">concept bool WeaklyIncrementable() {</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 return ranges::Semiregular&lt;I&gt;()</di=
v><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 &amp;&amp; requ=
ires(I i) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0typename ranges::difference_type_t&lt;I&gt;;</di=
v><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0requires ranges::SignedIntegral&lt;ranges::difference_type_t&l=
t;I&gt;&gt;();</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ ++i } -&gt; ranges::Same&lt;I&amp;&gt;; /*=
 not required to be equality preserving */</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0i++; /* not requi=
red to be equality preserving */</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0};</div><div class=3D"subprettyprint">}</=
div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">t=
emplate &lt;class I&gt;</div><div class=3D"subprettyprint">concept bool Ite=
rator() {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return ranges::W=
eaklyIncrementable&lt;I&gt;()</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 &amp;&amp; requires(I i) {</div><div class=3D"subprettypr=
int">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ *i } -&gt; au=
to&amp;&amp;; // Requires: i is dereferenceable</div><div class=3D"subprett=
yprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0};</div><div class=3D"subp=
rettyprint">}</div></font></div></code></div><br><font face=3D"georgia, ser=
if">A type satisfies &quot;concept template Iterator&quot; if and only if a=
ll the concepts above are satisfied! Shall we turn these stuff into a runti=
me wrapper? I suppose not, because that will introduce much runtime overhea=
d, and I prefer to define a proxy instead. After all, only 3 member functio=
ns is required to be abstract at runtime.</font></div><div><font face=3D"ge=
orgia, serif"><br></font></div><div><font face=3D"georgia, serif"><b style=
=3D"font-size: large;">The second reason is: Some concepts are difficult to=
 turn into specific type requirements so far.</b><br></font></div><div><fon=
t face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, seri=
f">It is true that we can turn some simple concepts into proxies. For examp=
le:</font></div><div><br></div><div><div class=3D"prettyprint" style=3D"bor=
der: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-color:=
 rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettypr=
int"><font color=3D"#660066"><div class=3D"subprettyprint">template &lt;cla=
ss T&gt;</div><div class=3D"subprettyprint">concept bool Foo() {</div><div =
class=3D"subprettyprint">=C2=A0 return requires(T t) {</div><div class=3D"s=
ubprettyprint">=C2=A0 =C2=A0 { t() };</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 { t.f() } -&gt; int;</div><div class=3D"subprettyprint">=C2=
=A0 }</div><div class=3D"subprettyprint">}</div><div class=3D"subprettyprin=
t"><br></div><div class=3D"subprettyprint">proxy Foo {</div><div class=3D"s=
ubprettyprint">=C2=A0 void operator()();</div><div class=3D"subprettyprint"=
>=C2=A0 int f();</div><div class=3D"subprettyprint">}</div></font></div></c=
ode></div><br><font face=3D"georgia, serif">But it is=C2=A0incredibly diffi=
cault for some other concepts. For example:</font></div><div><br></div><div=
><div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); =
word-wrap: break-word; background-color: rgb(250, 250, 250);"><code class=
=3D"prettyprint"><div class=3D"subprettyprint"><div class=3D"subprettyprint=
">template &lt;class T&gt;</div><div class=3D"subprettyprint">concept bool =
Foo() {</div><div class=3D"subprettyprint">=C2=A0 return requires(T t1, T t=
2, const T t3) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 t1.op_0(t=
2.op_1(t3.op_2()));</div><div class=3D"subprettyprint">=C2=A0 };</div><div =
class=3D"subprettyprint">}</div></div></code></div><br><font face=3D"georgi=
a, serif">It is easy to check whether the expressions are well-formed at co=
mpile-time for a concrete type T. But how can we abstract such type at runt=
ime?</font></div><div><font face=3D"georgia, serif"><br></font></div><div><=
font face=3D"georgia, serif">Mingxin Wang</font></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/78f335a4-a099-429d-bcd2-8fe3a9b185c1%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/78f335a4-a099-429d-bcd2-8fe3a9b185c1=
%40isocpp.org</a>.<br />

------=_Part_4273_623672606.1494436440350--

------=_Part_4272_35259288.1494436440349--

.


Author: Mingxin Wang <wmx16835vv@163.com>
Date: Fri, 12 May 2017 09:41:37 -0700 (PDT)
Raw View
------=_Part_1195_45595487.1494607298049
Content-Type: multipart/alternative;
 boundary="----=_Part_1196_1758937025.1494607298050"

------=_Part_1196_1758937025.1494607298050
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

To clarify the motivation and scope, Mr. Bengt Gustafsson and I have=20
discussed about this feature via email yesterday. Our opinions and=20
understanding are summarized as follows.

*What do we have now*

Before the =E2=80=9Cproxies=E2=80=9D, the most widely adopted method to imp=
lement=20
polymorphism in C++ is to use virtual functions, which exist from the very=
=20
beginning, and there is little update on this feature so far.

We used to define base classes with pure virtual functions, define derived=
=20
classes inheriting the base, and instantiate derived classes with dynamic=
=20
memory allocation, as is shown below:

class Base {
 public:
  virtual void f() =3D 0;
  virtual int g(double) =3D 0;
  virtual ~Base() {}

 protected:
  Base() =3D default;
};

class Derived : public Base {
 public:
  Derived() =3D default;
  void f() override;
  int g(double) override;
};

Base* base =3D new Derived();
base->f();
base->g(3);
delete base;

*What is the =E2=80=9Cproxies=E2=80=9D*

It is obvious that dynamic memory allocation is harmful to performance, but=
=20
why are we using it in the code above? Because, as we are using=20
polymorphism with a uniform base class, the implementation for the derived=
=20
class is completely unknown, including the memory required to construct the=
=20
derived class (*sizeof(Derived)*).

I have been trying to find out whether there is a better solution, and I=20
found it helpful to decouple the interfaces (the base classes) and the=20
implementations (the derived classes) with the =E2=80=9Cproxies=E2=80=9D, w=
hich is an=20
update version for virtual functions, as is shown below.

<https://lh3.googleusercontent.com/-3m2W7ogUxqE/WRXiIE3hI2I/AAAAAAAAAEY/A72=
ROREd4pg_fSbuhJ38_D80824FlOTbQCLcB/s1600/11.png>

The code above can be reconstructed with the =E2=80=9Cproxies=E2=80=9D, as =
is shown below:

proxy P {

  void f();

  int g(double);

};

=20

class T {

 public:

  void f();

  int g(double);

};

=20

T t;

P p(t);

p.f();
p.g(3);

Everything is so natural! The implementation only need to care about its=20
own semantics ignoring how it corresponds with the requirements (no=20
overriding any more), and no dynamic memory allocation happens at all!

Because the =E2=80=9Cproxies=E2=80=9D is an update version for virtual func=
tions, *it can=20
proxy any expression that can be declared virtual, including the overloads=
=20
and operators, but is not able to proxy the expressions that cannot be=20
declared virtual*, e.g. inner types, constructors. Thus, it is difficult to=
=20
convert every concept into a proxy, but on the contrary, it is easy to=20
generate a concept from any proxy.

*How should the compiler generate the code for a proxy?*

As Mr. Bengt Gustafsson wrote in the mail:

It would be good if your example was a little bit more elaborate than=20
> Runnable, for instance having a couple of named methods. As it stands tod=
ay=20
> it seems implementable as library-only as the operator()() which is the=
=20
> "key feature" here drowns in all the boilerplate methods. You could also=
=20
> add comments to make it obvious which sections contain the methods=20
> generated from the proxy declaration. Also you should not write "here is =
a=20
> possible implementation" as it suggests that this is code you should writ=
e=20
> yourself (defeating the whole purpose of the proposal) but "here is the=
=20
> equivalent of the code that the compiler would automatically generate for=
=20
> the proxy MyProxy".
>

Providing we have a proxy =E2=80=9CFoo=E2=80=9D declared as:

proxy Foo {
  void operator()();
  double f();
  void g(int);
};

Here is the equivalent of the code that the compiler would automatically=20
generate for the proxy:

class Foo {
 public:
  /* A template constructor */
  template <class Data>                                                    =
=20
    // Data is the concrete type
  Foo(Data& data) requires                                                =
=20
     // The parameter shall be passed as reference
      requires(Data data, int arg_0) {                                    =
=20
     // The auto-generated concept corresponding to the proxy
        { data() };
        { data.f() } -> double;
        { data.g(std::move(arg_0)) };
      } {
    Implementation<Data> a(data);                                          =
=20
    // A temporary value
    memcpy(data_, &a, sizeof(Abstraction));                                =
=20
    // Copy the implementation data to the char array byte by byte
  }
 =20
  /* Auto-generated constructors and operators */
  Foo() =3D default;
  Foo(Foo&&) =3D default;
  Foo(const Foo&) =3D default;
  Foo& operator=3D(Foo&&) =3D default;
  Foo& operator=3D(const Foo&) =3D default;

  /* Calling the corresponding member functions with the auto-generated=20
entries */
  void operator()() { reinterpret_cast<Abstraction*>(data_)->op_0(); }
  double f() { return reinterpret_cast<Abstraction*>(data_)->op_1(); }
  void g(int arg_0) {=20
reinterpret_cast<Abstraction*>(data_)->op_2(std::move(arg_0)); }

 private:
  class Abstraction {
   public:
    /* Stores a type-erased pointer */
    Abstraction(void* data) : data_(data) {}
   =20
    /* The pure virtual functions correspond to each expression declared in=
=20
the proxy respectively */
    virtual void op_0() =3D 0;
    virtual double op_1() =3D 0;
    virtual void op_2(int&&) =3D 0;                                        =
  =20
    // Every parameter is passed as rvalue
   =20
    /* A helper function */
    template <class T>
    T* get() { return static_cast<T*>(data_); }

   private:
    void* data_;
  };

  template <class Data>
  class Implementation final : public Abstraction {
   public:
    /* Initialize the base class */
    Implementation(Data& data) : Abstraction(&data) {}
   =20
    /* Implement the virtual functions with concrete function calls */
    void op_0() override { (*get<Data>())(); }
    double op_1() override { return get<Data>()->f(); }
    void op_2(int&& arg_0) override {=20
get<Data>()->g(std::forward<int>(arg_0)); } // The parameter shall be=20
forward to the concrete member functions
  };

  char data_[sizeof(Abstraction)];                                        =
=20
     // Declares a field large enough for any Implementation<T>
};

*In what way can and should predefined Concepts be reused to generate=20
abstract classes that forward functionality to concrete types? (possibly=20
not at all?)*

I insist that abstract classes shall not be generated from concepts,=20
because concepts can do a lot more than virtual functions, but it is=20
possible to generate a concept from any proxy for compile-time type safety.

As Mr. Bengt Gustafsson wrote in the mail:

Regarding the reuse of Concepts for this purpose I find it very elegant to=
=20
> do so. I would not be so afraid of the load on the compiler to disentangl=
e=20
> the concept hierarchy (it has to do this anyway to be able to see if a T=
=20
> fulfills a concept). However, I have a hard time understanding how the=20
> non-member requirements are to be translated to the corresponding proxy.=
=20
> For instance if we require that the type T fulfilling a concept Shiftable=
=20
> has a operator<<(ostream&, T), this would require the proxy to contain a=
=20
> virtual method with a signature like:
>
=20

virtual ostream& __leftshift(ostream&);

=20

and then have the compiler emit a call to it when it sees=20

proxy<Shiftable> p;

cout << p;

I guess this is doable, but it does complicate the implementation. What if=
=20
> there are two proxy parameters to a function (for different proxies) and=
=20
> then you try to multiply those values. Doesn't this create a need for=20
> multi-dispatch?


> Furthermore, I'm pretty sure that a concept can define that a complying=
=20
> type should have a certain method without specifying the return type of t=
he=20
> method as in:


> requres requires(Data& d) { d.myFunc(); }
>
=20

When we then try to create the proxy the return type of the created virtual=
=20
> function myFunc() is unknown!
>
=20

I don't want to rule out concepts as the basis for proxies but I think it=
=20
> needs a lot more thinking and that not all concepts will be possible to=
=20
> proxy, or maybe that the rules for how to write concepts need to be revis=
ed=20
> again to make proxying all concepts possible, but maybe concepts has=C2=
=B4ve=20
> gone too far now to be possible. Personally I don't care too much for=20
> concepts as they are going to be too cumbersome to use and will probably=
=20
> find little use outside the standard library. Especially with the contort=
ed=20
> syntax of the concepts TS it was really awful but I have seen that they a=
re=20
> cleaning up some of the mess more recently. I haven't followed these=20
> discussions too closely though.

=20

Also I think it is possible to write requirement like: requires { typename=
=20
> Data::value_type; } which just says that Data should have a nested type=
=20
> value_type without telling what it is. This is perfectly ok in the templa=
te=20
> world but fails utterly in the proxy realm.


*Ensure proper ownership management*

As Mr. Bengt Gustafsson wrote in the mail:

When it comes to lifetime handling I think that Jakob Riedle is right in=20
> that we should strive for getting the same type of semantics as for regul=
ar=20
> types, as he showed in his code box. I think this means that there must b=
e=20
> some more magic in the proxy code as it will optionally own the data=20
> itself. The sad part is that now it becomes hard to see how shared_ptr<T>=
=20
> and shared_ptr<MyProxy> could co-exist pointing to the same T object (T=
=20
> fulfilling MyProxy of course). But this may be a necessary sacrifice as w=
e=20
> can't support all user written shared pointers out there anyway. Or maybe=
=20
> it can be supported (similarly to how a shared_ptr<BASE> can be assigned=
=20
> from a shared_ptr<DERIVED> and they still share the refcount. This will=
=20
> require some surgery in the shared_ptr class I suspect. Thinking about th=
e=20
> details of this will reveal new insights, no doubt.
>

This is a question I've been thinking about over and over again. On the one=
=20
hand, if the lifetime issue is coupled with the =E2=80=9Cproxies=E2=80=9D, =
it violates the=20
single responsibility principle, and it becomes unfriendly to =E2=80=9Cstac=
k=20
objects=E2=80=9D, whose lifetime is controlled by the execution of program,=
 but it=20
seems to be easier to use. On the other hand, if the lifetime issue is=20
decoupled from the =E2=80=9Cproxies=E2=80=9D, users are responsible for man=
aging the=20
lifetime, however, they are free to specify the algorithms (for =E2=80=9Che=
ap=20
objects=E2=80=9D, from new/delete to GC).

After some research, I found it unnecessary to couple the lifetime issue=20
with the =E2=80=9Cproxies=E2=80=9D at all, because most situations that req=
uire=20
polymorphism are implementable without dynamic memory allocation, as the=20
example mentioned earlier demonstrates.

If a proxy is used asynchronously, it is required to construct the object=
=20
on the heap. We can use =E2=80=9CAsync Concurrent Invoke=E2=80=9D (defined =
in =E2=80=9CStructural=20
Support for C++ Concurrency=E2=80=9D, P0642, available here=20
<https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/tQb9t6H=
nu6M>)=20
and delete the object in the callback, as is shown below:

Object* object =3D new Object(...); // The data to be used asynchronously
P p(*object); // Declaring a proxy
con::async_concurrent_invoke([=3D] { delete object; }, /* some concurrent=
=20
callers */);

*Should "Static" concepts behave like "dynamic" ones only in that they=20
operate at compile time? Why is a different approach preferable?*

As Mr. Bengt Gustafsson wrote in the mail:

Finally, if concepts are to be involved as the way to specify contents of=
=20
> proxies we could maybe solve the syntactical problems using a "magic"=20
> library template which could be called dynamic, box, proxy or something. =
In=20
> general I don't like mixing up library with language, but as it seems ver=
y=20
> hard to figure out a useful syntax in another way here we go:
>
=20

std::box<Callable<void()>> myFunction;      // Works essentially as=20
> std::function
> std::box<MyConcept> x;
>
> Then we can have two functions:
>
> void Func(MyConcept& p);                        // This is implicitly a=
=20
> template function as MyConcept is a concept (using terse template syntax)
>
> void Func(std::box<MyConcept>& p);       // This is a regular function=20
> taking a magic box wrapping any object complying to MyConcept.
>
> However, I don't think box is the best name as it doesn't really do=20
> _exactly_ what boxing in other languages does.


As I suppose that abstract classes shall not be generated from concepts, I=
=20
do not vote for this idea. Besides, because this feature requires code=20
generation at compile-time, I tend to define the =E2=80=9Cproxies=E2=80=9D =
as a =E2=80=9Ctype of=20
type=E2=80=9D rather than a =E2=80=9Ctemplate <typename...> typename=E2=80=
=9D.

Mingxin Wang

--=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/f6c3b3d1-f723-41de-ac23-85defc434abe%40isocpp.or=
g.

------=_Part_1196_1758937025.1494607298050
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div><span lang=3D"EN-US"><font face=3D"georgia, serif">To=
 clarify the motivation and scope, Mr. Bengt Gustafsson and I have discusse=
d about this feature via email yesterday. Our opinions and understanding ar=
e=C2=A0</font></span><span style=3D"font-family: georgia, serif;">summarize=
d</span><span style=3D"font-family: georgia, serif;">=C2=A0as follows.</spa=
n></div><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><br></font>=
</span></div><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><font =
size=3D"4"><b>What do we have now</b></font><br></font></span></div><div><s=
pan lang=3D"EN-US"><font face=3D"georgia, serif"><br></font></span></div><d=
iv><span lang=3D"EN-US"><div style=3D"font-family: georgia, serif;">Before =
the =E2=80=9Cproxies=E2=80=9D, the most widely adopted method to implement =
polymorphism in C++ is to use virtual functions, which exist from the very =
beginning, and there is little update on this feature so far.</div><div sty=
le=3D"font-family: georgia, serif;"><br></div><div style=3D"font-family: ge=
orgia, serif;">We used to define base classes with pure virtual functions, =
define derived classes inheriting the base, and instantiate derived classes=
 with dynamic memory allocation, as is shown below:</div><div style=3D"font=
-family: georgia, serif;"><br></div><div><div class=3D"prettyprint" style=
=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background=
-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subp=
rettyprint"><font color=3D"#660066"><div class=3D"subprettyprint">class Bas=
e {</div><div class=3D"subprettyprint">=C2=A0public:</div><div class=3D"sub=
prettyprint">=C2=A0 virtual void f() =3D 0;</div><div class=3D"subprettypri=
nt">=C2=A0 virtual int g(double) =3D 0;</div><div class=3D"subprettyprint">=
=C2=A0 virtual ~Base() {}</div><div class=3D"subprettyprint"><br></div><div=
 class=3D"subprettyprint">=C2=A0protected:</div><div class=3D"subprettyprin=
t">=C2=A0 Base() =3D default;</div><div class=3D"subprettyprint">};</div><d=
iv class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">class D=
erived : public Base {</div><div class=3D"subprettyprint">=C2=A0public:</di=
v><div class=3D"subprettyprint">=C2=A0 Derived() =3D default;</div><div cla=
ss=3D"subprettyprint">=C2=A0 void f() override;</div><div class=3D"subprett=
yprint">=C2=A0 int g(double) override;</div><div class=3D"subprettyprint">}=
;</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint=
">Base* base =3D new Derived();</div><div class=3D"subprettyprint">base-&gt=
;f();</div><div class=3D"subprettyprint">base-&gt;g(3);</div><div class=3D"=
subprettyprint">delete base;</div></font></div></code></div><br><font face=
=3D"georgia, serif" size=3D"4"><b>What is the =E2=80=9Cproxies=E2=80=9D</b>=
</font><br></div></span></div><div><span lang=3D"EN-US"><font face=3D"georg=
ia, serif"><br></font></span></div><div><span lang=3D"EN-US"><font face=3D"=
georgia, serif"><div>It is obvious that dynamic memory allocation is harmfu=
l to performance, but why are we using it in the code above? Because, as we=
 are using polymorphism with a uniform base class, the implementation for t=
he derived class is completely unknown, including the memory required to co=
nstruct the derived class (<i>sizeof(Derived)</i>).</div><div><br></div><di=
v>I have been trying to find out whether there is a better solution, and I =
found it helpful to decouple the interfaces (the base classes) and the impl=
ementations (the derived classes) with the =E2=80=9Cproxies=E2=80=9D, which=
 is an update version for virtual functions, as is shown below.</div><div><=
br></div></font></span></div><p class=3D"separator" style=3D"text-align: ce=
nter; clear: both;"><a imageanchor=3D"1" href=3D"https://lh3.googleusercont=
ent.com/-3m2W7ogUxqE/WRXiIE3hI2I/AAAAAAAAAEY/A72ROREd4pg_fSbuhJ38_D80824FlO=
TbQCLcB/s1600/11.png" style=3D"margin-left: 1em; margin-right: 1em;"><img s=
rc=3D"https://lh3.googleusercontent.com/-3m2W7ogUxqE/WRXiIE3hI2I/AAAAAAAAAE=
Y/A72ROREd4pg_fSbuhJ38_D80824FlOTbQCLcB/s400/11.png" border=3D"0" width=3D"=
400" height=3D"216"></a></p><div><span lang=3D"EN-US"><font face=3D"georgia=
, serif"><br></font></span></div><div><span lang=3D"EN-US"><font face=3D"ge=
orgia, serif">The code above can be reconstructed with the =E2=80=9Cproxies=
=E2=80=9D, as is shown below:<br></font></span></div><div><span lang=3D"EN-=
US"><font face=3D"georgia, serif"><br></font></span></div><div><span lang=
=3D"EN-US"><font face=3D"georgia, serif"><div class=3D"prettyprint" style=
=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background=
-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subp=
rettyprint"><p class=3D"MsoNormal"><span lang=3D"EN-US">proxy P {<o:p></o:p=
></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0
void f();<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0 int
g(double);<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">};<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">class T {<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0public:<o:p></o:p></span>=
</p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0
void f();<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0 int
g(double);<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">};<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">T t;<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">P p(t);<o:p></o:p></span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">p.f();<o:p></o:p></span></p>

<span lang=3D"EN-US" style=3D"font-size:10.0pt;mso-bidi-font-size:11.0pt;fo=
nt-family:
&quot;Times New Roman&quot;,serif;mso-fareast-font-family:=E5=BE=AE=E8=BD=
=AF=E9=9B=85=E9=BB=91;mso-font-kerning:1.0pt;
mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA"=
>p.g(3);</span><br></div></code></div><br><div>Everything is so natural! Th=
e implementation only need to care about its own semantics ignoring how it =
corresponds with the requirements (no overriding any more), and no dynamic =
memory allocation happens at all!</div><div><br></div><div>Because the =E2=
=80=9Cproxies=E2=80=9D is an update version for virtual functions, <b>it ca=
n proxy any expression that can be declared virtual, including the overload=
s and operators, but is not able to proxy the expressions that cannot be de=
clared virtual</b>, e.g. inner types, constructors. Thus, it is difficult t=
o convert every concept into a proxy, but on the contrary, it is easy to ge=
nerate a concept from any proxy.</div></font></span></div><div><span lang=
=3D"EN-US"><font face=3D"georgia, serif"><br></font></span></div><div><span=
 lang=3D"EN-US"><font face=3D"georgia, serif"><font size=3D"4"><b>How shoul=
d the compiler generate the code for a proxy?</b></font><br></font></span><=
/div><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><br></font></s=
pan></div><div><span lang=3D"EN-US"><span lang=3D"EN-US" style=3D"font-size=
:10.0pt;mso-bidi-font-size:
11.0pt;font-family:&quot;Times New Roman&quot;,serif;mso-fareast-font-famil=
y:=E5=BE=AE=E8=BD=AF=E9=9B=85=E9=BB=91;
mso-font-kerning:1.0pt;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;
mso-bidi-language:AR-SA">As Mr. Bengt Gustafsson wrote in the mail:</span><=
font face=3D"georgia, serif"><br></font></span></div><div><span lang=3D"EN-=
US"><span lang=3D"EN-US" style=3D"font-size:10.0pt;mso-bidi-font-size:
11.0pt;font-family:&quot;Times New Roman&quot;,serif;mso-fareast-font-famil=
y:=E5=BE=AE=E8=BD=AF=E9=9B=85=E9=BB=91;
mso-font-kerning:1.0pt;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;
mso-bidi-language:AR-SA"><br></span></span></div><blockquote class=3D"gmail=
_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-=
left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex=
;"><span lang=3D"EN-US"><span lang=3D"EN-US"><font face=3D"Times New Roman,=
 serif"><span style=3D"font-size: 13.3333px;">It would be good if your exam=
ple was a little bit more elaborate than Runnable, for instance having a co=
uple of named methods. As it stands today it seems implementable as library=
-only as the operator()() which is the &quot;key feature&quot; here drowns =
in all the boilerplate methods. You could also add comments to make it obvi=
ous which sections contain the methods generated from the proxy declaration=
.. Also you should not write &quot;here is a possible implementation&quot; a=
s it suggests that this is code you should write yourself (defeating the wh=
ole purpose of the proposal) but &quot;here is the equivalent of the code t=
hat the compiler would automatically generate for the proxy MyProxy&quot;.<=
/span></font><br></span></span></blockquote><div><span lang=3D"EN-US"><font=
 face=3D"georgia, serif"><br></font></span></div><div><span lang=3D"EN-US">=
<font face=3D"georgia, serif">Providing we have a proxy =E2=80=9CFoo=E2=80=
=9D declared as:<br></font></span></div><div><span lang=3D"EN-US"><font fac=
e=3D"georgia, serif"><br></font></span></div><div><span lang=3D"EN-US"><fon=
t face=3D"georgia, serif"><div class=3D"prettyprint" style=3D"border: 1px s=
olid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(250, =
250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><div =
class=3D"subprettyprint">proxy Foo {</div><div class=3D"subprettyprint">=C2=
=A0 void operator()();</div><div class=3D"subprettyprint">=C2=A0 double f()=
;</div><div class=3D"subprettyprint">=C2=A0 void g(int);</div><div class=3D=
"subprettyprint">};</div></div></code></div><br>Here is the equivalent of t=
he code that the compiler would automatically generate for the proxy:<br></=
font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><=
br></font></span></div><div><span lang=3D"EN-US"><div class=3D"prettyprint"=
 style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; back=
ground-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><font color=3D"#660066"><div class=3D"subprettyprint">c=
lass Foo {</div><div class=3D"subprettyprint">=C2=A0public:</div><div class=
=3D"subprettyprint">=C2=A0 /* A template constructor */</div><div class=3D"=
subprettyprint">=C2=A0 template &lt;class Data&gt; =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 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 // Data is the concrete type</div><div class=3D"su=
bprettyprint">=C2=A0 Foo(Data&amp; data) requires =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 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0// The parameter shall be passed as reference</div><div cl=
ass=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 requires(Data data, int arg_0) =
{ =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 =C2=A0 =C2=A0 =C2=A0//=
 The auto-generated concept corresponding to the proxy</div><div class=3D"s=
ubprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 { data() };</div><div class=3D"s=
ubprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 { data.f() } -&gt; double;</div>=
<div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 { data.g(std::mov=
e(arg_0)) };</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 } {</d=
iv><div class=3D"subprettyprint">=C2=A0 =C2=A0 Implementation&lt;Data&gt; a=
(data); =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 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 // A temporary value</div><div class=3D"subprettyprint=
">=C2=A0 =C2=A0 memcpy(data_, &amp;a, sizeof(Abstraction)); =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 // Copy the implementation data to t=
he char array byte by byte</div><div class=3D"subprettyprint">=C2=A0 }</div=
><div class=3D"subprettyprint">=C2=A0=C2=A0</div><div class=3D"subprettypri=
nt">=C2=A0 /* Auto-generated constructors and operators */</div><div class=
=3D"subprettyprint">=C2=A0 Foo() =3D default;</div><div class=3D"subprettyp=
rint">=C2=A0 Foo(Foo&amp;&amp;) =3D default;</div><div class=3D"subprettypr=
int">=C2=A0 Foo(const Foo&amp;) =3D default;</div><div class=3D"subprettypr=
int">=C2=A0 Foo&amp; operator=3D(Foo&amp;&amp;) =3D default;</div><div clas=
s=3D"subprettyprint">=C2=A0 Foo&amp; operator=3D(const Foo&amp;) =3D defaul=
t;</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprin=
t">=C2=A0 /* Calling the corresponding member functions with the auto-gener=
ated entries */</div><div class=3D"subprettyprint">=C2=A0 void operator()()=
 { reinterpret_cast&lt;Abstraction*&gt;(data_)-&gt;op_0(); }</div><div clas=
s=3D"subprettyprint">=C2=A0 double f() { return reinterpret_cast&lt;Abstrac=
tion*&gt;(data_)-&gt;op_1(); }</div><div class=3D"subprettyprint">=C2=A0 vo=
id g(int arg_0) { reinterpret_cast&lt;Abstraction*&gt;(data_)-&gt;op_2(std:=
:move(arg_0)); }</div><div class=3D"subprettyprint"><br></div><div class=3D=
"subprettyprint">=C2=A0private:</div><div class=3D"subprettyprint">=C2=A0 c=
lass Abstraction {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0public:<=
/div><div class=3D"subprettyprint">=C2=A0 =C2=A0 /* Stores a type-erased po=
inter */</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 Abstraction(void*=
 data) : data_(data) {}</div><div class=3D"subprettyprint">=C2=A0 =C2=A0=C2=
=A0</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 /* The pure virtual fu=
nctions correspond to each expression declared in the proxy respectively */=
</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 virtual void op_0() =3D 0=
;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 virtual double op_1() =
=3D 0;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 virtual void op_2(i=
nt&amp;&amp;) =3D 0; =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 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // Every parameter is passed as rvalue</=
div><div class=3D"subprettyprint">=C2=A0 =C2=A0=C2=A0</div><div class=3D"su=
bprettyprint">=C2=A0 =C2=A0 /* A helper function */</div><div class=3D"subp=
rettyprint">=C2=A0 =C2=A0 template &lt;class T&gt;</div><div class=3D"subpr=
ettyprint">=C2=A0 =C2=A0 T* get() { return static_cast&lt;T*&gt;(data_); }<=
/div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0private:</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 void=
* data_;</div><div class=3D"subprettyprint">=C2=A0 };</div><div class=3D"su=
bprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 template &lt;c=
lass Data&gt;</div><div class=3D"subprettyprint">=C2=A0 class Implementatio=
n final : public Abstraction {</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0public:</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 /* Initializ=
e the base class */</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 Implem=
entation(Data&amp; data) : Abstraction(&amp;data) {}</div><div class=3D"sub=
prettyprint">=C2=A0 =C2=A0=C2=A0</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0 /* Implement the virtual functions with concrete function calls */</=
div><div class=3D"subprettyprint">=C2=A0 =C2=A0 void op_0() override { (*ge=
t&lt;Data&gt;())(); }</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 doub=
le op_1() override { return get&lt;Data&gt;()-&gt;f(); }</div><div class=3D=
"subprettyprint">=C2=A0 =C2=A0 void op_2(int&amp;&amp; arg_0) override { ge=
t&lt;Data&gt;()-&gt;g(std::forward&lt;int&gt;(arg_0)); } // The parameter s=
hall be forward to the concrete member functions</div><div class=3D"subpret=
typrint">=C2=A0 };</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">=C2=A0 char data_[sizeof(Abstraction)]; =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 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0//=
 Declares a field large enough for any Implementation&lt;T&gt;</div><div cl=
ass=3D"subprettyprint">};</div></font></div></code></div><font face=3D"geor=
gia, serif"><br><font size=3D"4"><b>In what way can and should predefined C=
oncepts be reused to generate abstract classes that forward functionality t=
o concrete types? (possibly not at all?)</b></font><br></font></span></div>=
<div><span lang=3D"EN-US"><font face=3D"georgia, serif"><br></font></span><=
/div><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><div>I insist =
that abstract classes shall not be generated from concepts, because concept=
s can do a lot more than virtual functions, but it is possible to generate =
a concept from any proxy for compile-time type safety.</div><div><br></div>=
<div>As Mr. Bengt Gustafsson wrote in the mail:</div></font></span></div><d=
iv><span lang=3D"EN-US"><font face=3D"georgia, serif"><br></font></span></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; bo=
rder-left-width: 1px; border-left-style: solid; border-left-color: rgb(204,=
 204, 204); padding-left: 1ex;"><span lang=3D"EN-US"><font face=3D"georgia,=
 serif">Regarding the reuse of Concepts for this purpose I find it very ele=
gant to do so. I would not be so afraid of the load on the compiler to dise=
ntangle the concept hierarchy (it has to do this anyway to be able to see i=
f a T fulfills a concept). However, I have a hard time understanding how th=
e non-member requirements are to be translated to the corresponding proxy. =
For instance if we require that the type T fulfilling a concept Shiftable h=
as a operator&lt;&lt;(ostream&amp;, T), this would require the proxy to con=
tain a virtual method with a signature like:<br></font></span></blockquote>=
<blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; borde=
r-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 20=
4, 204); padding-left: 1ex;"><font face=3D"georgia, serif">=C2=A0</font></b=
lockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.=
8ex; border-left-width: 1px; border-left-style: solid; border-left-color: r=
gb(204, 204, 204); padding-left: 1ex;"><font face=3D"georgia, serif">virtua=
l ostream&amp; __leftshift(ostream&amp;);</font></blockquote><blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: =
1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); paddi=
ng-left: 1ex;"><font face=3D"georgia, serif">=C2=A0</font></blockquote><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-le=
ft-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 2=
04); padding-left: 1ex;"><font face=3D"georgia, serif">and then have the co=
mpiler emit a call to it when it sees=C2=A0</font></blockquote><blockquote =
class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width=
: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); pad=
ding-left: 1ex;"><font face=3D"georgia, serif">proxy&lt;Shiftable&gt; p;</f=
ont></blockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px=
 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-c=
olor: rgb(204, 204, 204); padding-left: 1ex;"><font face=3D"georgia, serif"=
>cout &lt;&lt; p;</font></blockquote><blockquote class=3D"gmail_quote" styl=
e=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: =
solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><font fac=
e=3D"georgia, serif">I guess this is doable, but it does complicate the imp=
lementation. What if there are two proxy parameters to a function (for diff=
erent proxies) and then you try to multiply those values. Doesn&#39;t this =
create a need for multi-dispatch?</font></blockquote><blockquote class=3D"g=
mail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; bor=
der-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left:=
 1ex;"><font face=3D"georgia, serif"><br></font></blockquote><blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: =
1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); paddi=
ng-left: 1ex;"><font face=3D"georgia, serif">Furthermore, I&#39;m pretty su=
re that a concept can define that a complying type should have a certain me=
thod without specifying the return type of the method as in:</font></blockq=
uote><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; =
border-left-width: 1px; border-left-style: solid; border-left-color: rgb(20=
4, 204, 204); padding-left: 1ex;"><br></blockquote><blockquote class=3D"gma=
il_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; borde=
r-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1=
ex;"><font face=3D"georgia, serif">requres requires(Data&amp; d) { d.myFunc=
(); }<br></font></blockquote><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; b=
order-left-color: rgb(204, 204, 204); padding-left: 1ex;"><font face=3D"geo=
rgia, serif">=C2=A0</font></blockquote><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style=
: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><font f=
ace=3D"georgia, serif">When we then try to create the proxy the return type=
 of the created virtual function myFunc() is unknown!</font><br></blockquot=
e><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; bor=
der-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, =
204, 204); padding-left: 1ex;"><font face=3D"georgia, serif">=C2=A0</font><=
/blockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px =
0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color:=
 rgb(204, 204, 204); padding-left: 1ex;"><font face=3D"georgia, serif">I do=
n&#39;t want to rule out concepts as the basis for proxies but I think it n=
eeds a lot more thinking and that not all concepts will be possible to prox=
y, or maybe that the rules for how to write concepts need to be revised aga=
in to make proxying all concepts possible, but maybe concepts has=C2=B4ve g=
one too far now to be possible. Personally I don&#39;t care too much for co=
ncepts as they are going to be too cumbersome to use and will probably find=
 little use outside the standard library. Especially with the contorted syn=
tax of the concepts TS it was really awful but I have seen that they are cl=
eaning up some of the mess more recently. I haven&#39;t followed these disc=
ussions too closely though.</font></blockquote><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-le=
ft-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"=
><font face=3D"georgia, serif">=C2=A0</font></blockquote><blockquote class=
=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px=
; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-=
left: 1ex;"><font face=3D"georgia, serif">Also I think it is possible to wr=
ite requirement like: requires { typename Data::value_type; } which just sa=
ys that Data should have a nested type value_type without telling what it i=
s. This is perfectly ok in the template world but fails utterly in the prox=
y realm.</font></blockquote><div><span lang=3D"EN-US"><font face=3D"georgia=
, serif"><br></font></span></div><div><span lang=3D"EN-US"><font face=3D"ge=
orgia, serif"><font size=3D"4"><b>Ensure proper ownership management</b></f=
ont><br></font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia=
, serif"><br></font></span></div><div><span lang=3D"EN-US"><font face=3D"ge=
orgia, serif">As Mr. Bengt Gustafsson wrote in the mail:<br></font></span><=
/div><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><br></font></s=
pan></div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.=
8ex; border-left-width: 1px; border-left-style: solid; border-left-color: r=
gb(204, 204, 204); padding-left: 1ex;"><span lang=3D"EN-US"><font face=3D"g=
eorgia, serif">When it comes to lifetime handling I think that Jakob Riedle=
 is right in that we should strive for getting the same type of semantics a=
s for regular types, as he showed in his code box. I think this means that =
there must be some more magic in the proxy code as it will optionally own t=
he data itself. The sad part is that now it becomes hard to see how shared_=
ptr&lt;T&gt; and shared_ptr&lt;MyProxy&gt; could co-exist pointing to the s=
ame T object (T fulfilling MyProxy of course). But this may be a necessary =
sacrifice as we can&#39;t support all user written shared pointers out ther=
e anyway. Or maybe it can be supported (similarly to how a shared_ptr&lt;BA=
SE&gt; can be assigned from a shared_ptr&lt;DERIVED&gt; and they still shar=
e the refcount. This will require some surgery in the shared_ptr class I su=
spect. Thinking about the details of this will reveal new insights, no doub=
t.<br></font></span></blockquote><div><span lang=3D"EN-US"><font face=3D"ge=
orgia, serif"><br></font></span></div><div><span lang=3D"EN-US"><div style=
=3D"font-family: georgia, serif;">This is a question I&#39;ve been thinking=
 about over and over again. On the one hand, if the lifetime issue is coupl=
ed with the =E2=80=9Cproxies=E2=80=9D, it violates the single responsibilit=
y principle, and it becomes unfriendly to =E2=80=9Cstack objects=E2=80=9D, =
whose lifetime is controlled by the execution of program, but it seems to b=
e easier to use. On the other hand, if the lifetime issue is decoupled from=
 the =E2=80=9Cproxies=E2=80=9D, users are responsible for managing the life=
time, however, they are free to specify the algorithms (for =E2=80=9Cheap o=
bjects=E2=80=9D, from new/delete to GC).</div><div style=3D"font-family: ge=
orgia, serif;"><br></div><div style=3D"font-family: georgia, serif;">After =
some research, I found it unnecessary to couple the lifetime issue with the=
 =E2=80=9Cproxies=E2=80=9D at all, because most situations that require pol=
ymorphism are implementable without dynamic memory allocation, as the examp=
le mentioned earlier demonstrates.</div><div style=3D"font-family: georgia,=
 serif;"><br></div><div style=3D"font-family: georgia, serif;">If a proxy i=
s used asynchronously, it is required to construct the object on the heap. =
We can use =E2=80=9CAsync Concurrent Invoke=E2=80=9D (defined in =E2=80=9CS=
tructural Support for C++ Concurrency=E2=80=9D, P0642, <a href=3D"https://g=
roups.google.com/a/isocpp.org/forum/#!topic/std-proposals/tQb9t6Hnu6M">avai=
lable here</a>) and delete the object in the callback, as is shown below:</=
div><div style=3D"font-family: georgia, serif;"><br></div><div style=3D"fon=
t-family: georgia, serif;"><div class=3D"prettyprint" style=3D"border: 1px =
solid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(250,=
 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><div=
 class=3D"subprettyprint">Object* object =3D new Object(...); // The data t=
o be used asynchronously</div><div class=3D"subprettyprint">P p(*object); /=
/ Declaring a proxy</div><div class=3D"subprettyprint">con::async_concurren=
t_invoke([=3D] { delete object; }, /* some concurrent callers */);</div></d=
iv></code></div><br><b><font size=3D"4">Should &quot;Static&quot; concepts =
behave like &quot;dynamic&quot; ones only in that they operate at compile t=
ime? Why is a different approach preferable?</font></b><br></div><div style=
=3D"font-family: georgia, serif;"><br></div><div style=3D"font-family: geor=
gia, serif;">As Mr. Bengt Gustafsson wrote in the mail:<br></div><div style=
=3D"font-family: georgia, serif;"><br></div><blockquote class=3D"gmail_quot=
e" style=3D"font-family: georgia, serif; margin: 0px 0px 0px 0.8ex; border-=
left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204,=
 204); padding-left: 1ex;">Finally, if concepts are to be involved as the w=
ay to specify contents of proxies we could maybe solve the syntactical prob=
lems using a &quot;magic&quot; library template which could be called dynam=
ic, box, proxy or something. In general I don&#39;t like mixing up library =
with language, but as it seems very hard to figure out a useful syntax in a=
nother way here we go:<br></blockquote><blockquote class=3D"gmail_quote" st=
yle=3D"font-family: georgia, serif; margin: 0px 0px 0px 0.8ex; border-left-=
width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204)=
; padding-left: 1ex;">=C2=A0</blockquote><blockquote class=3D"gmail_quote" =
style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-sty=
le: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><div =
class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-w=
rap: break-word; background-color: rgb(250, 250, 250);"><code class=3D"pret=
typrint"><div class=3D"subprettyprint"><font color=3D"#660066"><div class=
=3D"subprettyprint">std::box&lt;Callable&lt;void()&gt;&gt; myFunction; =C2=
=A0 =C2=A0 =C2=A0// Works essentially as std::function</div><div class=3D"s=
ubprettyprint">std::box&lt;MyConcept&gt; x;</div><div class=3D"subprettypri=
nt"><br></div><div class=3D"subprettyprint">Then we can have two functions:=
</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint"=
>void Func(MyConcept&amp; p); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// This is implicitly a template func=
tion as MyConcept is a concept (using terse template syntax)</div><div clas=
s=3D"subprettyprint"><br></div><div class=3D"subprettyprint">void Func(std:=
:box&lt;MyConcept&gt;&amp; p); =C2=A0 =C2=A0 =C2=A0 // This is a regular fu=
nction taking a magic box wrapping any object complying to MyConcept.</div>=
</font></div></code></div><br></blockquote><blockquote class=3D"gmail_quote=
" style=3D"margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-s=
tyle: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><fo=
nt face=3D"georgia, serif">However, I don&#39;t think box is the best name =
as it doesn&#39;t really do _exactly_ what boxing in other languages does.<=
/font></blockquote><div style=3D"font-family: georgia, serif;"><br></div><d=
iv><font face=3D"georgia, serif">As I suppose that abstract classes shall n=
ot be generated from concepts, I do not vote for this idea. Besides, becaus=
e this feature requires code generation at compile-time, I tend to define t=
he =E2=80=9Cproxies=E2=80=9D as a =E2=80=9Ctype of type=E2=80=9D rather tha=
n a =E2=80=9Ctemplate &lt;typename...&gt; typename=E2=80=9D.</font><br></di=
v><div><font face=3D"georgia, serif"><br></font></div><div><font face=3D"ge=
orgia, serif">Mingxin Wang</font></div></span></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/f6c3b3d1-f723-41de-ac23-85defc434abe%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/f6c3b3d1-f723-41de-ac23-85defc434abe=
%40isocpp.org</a>.<br />

------=_Part_1196_1758937025.1494607298050--

------=_Part_1195_45595487.1494607298049--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 12 May 2017 14:28:02 -0700 (PDT)
Raw View
------=_Part_131_235314462.1494624482217
Content-Type: multipart/alternative;
 boundary="----=_Part_132_1202200125.1494624482218"

------=_Part_132_1202200125.1494624482218
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Things your design is potentially lacking (which aren't covered in the meat=
=20
of my reply):

Proxies need an equivalent of `dynamic_cast`. Or rather, an equivalent of=
=20
`any_cast`, which is effectively the same thing. You need to be able to=20
extract the type back out of the proxy. And it must be the exact type you=
=20
provided the proxy.

Also, I think we need proxy maps. Remember the old C++11 concepts with=20
concept maps, which were basically ways to coerce a type to fit a concept=
=20
it doesn't really fit? I think this would be *very* useful for proxies.

A proxy map is a type which implements a particular proxy for a particular=
=20
given type(s), as defined as a template. Consider a callable proxy. That=20
works well enough for class types, but what if you want your callable to be=
=20
able to use function pointers or member pointers? You need some kind of=20
class type to do the translation there.

That would be the point of the proxy map. For a given proxy and for a given=
=20
type (or range of types), you create a class. When a user tries to turn one=
=20
of those types into that class, it results in the construction of a proxy=
=20
map type with that value, which is then passed into the proxy type.

Unless you can come up with a more elegant way to handle non-class types,=
=20
or types that don't quite fit a proxy.

Basically, my litmus test for proxy design is this: the design is deficient=
=20
if you cannot implement `std::function` by using a proxy.

On Friday, May 12, 2017 at 12:41:38 PM UTC-4, Mingxin Wang wrote:
>
> To clarify the motivation and scope, Mr. Bengt Gustafsson and I have=20
> discussed about this feature via email yesterday. Our opinions and=20
> understanding are summarized as follows.
>
> *What do we have now*
>
> Before the =E2=80=9Cproxies=E2=80=9D, the most widely adopted method to i=
mplement=20
> polymorphism in C++ is to use virtual functions, which exist from the ver=
y=20
> beginning, and there is little update on this feature so far.
>
> We used to define base classes with pure virtual functions, define derive=
d=20
> classes inheriting the base, and instantiate derived classes with dynamic=
=20
> memory allocation, as is shown below:
>
> class Base {
>  public:
>   virtual void f() =3D 0;
>   virtual int g(double) =3D 0;
>   virtual ~Base() {}
>
>  protected:
>   Base() =3D default;
> };
>
> class Derived : public Base {
>  public:
>   Derived() =3D default;
>   void f() override;
>   int g(double) override;
> };
>
> Base* base =3D new Derived();
> base->f();
> base->g(3);
> delete base;
>
> *What is the =E2=80=9Cproxies=E2=80=9D*
>
> It is obvious that dynamic memory allocation is harmful to performance,=
=20
> but why are we using it in the code above? Because, as we are using=20
> polymorphism with a uniform base class, the implementation for the derive=
d=20
> class is completely unknown, including the memory required to construct t=
he=20
> derived class (*sizeof(Derived)*).
>

Nobody forced you to allocate memory. You could just as easily have done:

Derived d{};
Base *base =3D &d;
//etc.

I have been trying to find out whether there is a better solution, and I=20
> found it helpful to decouple the interfaces (the base classes) and the=20
> implementations (the derived classes) with the =E2=80=9Cproxies=E2=80=9D,=
 which is an=20
> update version for virtual functions, as is shown below.
>
>
> <https://lh3.googleusercontent.com/-3m2W7ogUxqE/WRXiIE3hI2I/AAAAAAAAAEY/A=
72ROREd4pg_fSbuhJ38_D80824FlOTbQCLcB/s1600/11.png>
>
> The code above can be reconstructed with the =E2=80=9Cproxies=E2=80=9D, a=
s is shown below:
>
> proxy P {
>
>   void f();
>
>   int g(double);
>
> };
>
> =20
>
> class T {
>
>  public:
>
>   void f();
>
>   int g(double);
>
> };
>
> =20
>
> T t;
>
> P p(t);
>
> p.f();
> p.g(3);
>
> Everything is so natural! The implementation only need to care about its=
=20
> own semantics ignoring how it corresponds with the requirements (no=20
> overriding any more), and no dynamic memory allocation happens at all!
>

The only difference between that and what I did up there is that there's no=
=20
need to dereference `t` when storing it in a `p`. If this is intended to be=
=20
a motivation for proxies, it doesn't really work.

A much better motivation for them is, well, pretty much any case for=20
type-erasure (since despite your attempt to call it something else, this is=
=20
clearly language-based type-erasure). One of the main reasons for=20
type-erasure is to provide polymorphism *without* being invasive. So it's=
=20
about working with types that don't have base classes, which you personally=
=20
do not own and therefore cannot give them base classes.

And equally importantly, types where you don't *want* to give them base=20
classes. Like `std::string`.

Because the =E2=80=9Cproxies=E2=80=9D is an update version for virtual func=
tions, *it can=20
> proxy any expression that can be declared virtual, including the overload=
s=20
> and operators, but is not able to proxy the expressions that cannot be=20
> declared virtual*, e.g. inner types, constructors.
>

No.

We're talking about a *language feature*. You should not limit the behavior=
=20
of a language feature simply because the analogy no longer fits. If a=20
"proxy" *genuinely* cannot be implemented which can forward certain=20
constructs, so be it. But you shouldn't limit the design just to things=20
that can be declared with virtual functions simply because it doesn't fit=
=20
into the analogy you built for it.

That doesn't mean we have to do it through concepts, of course. But the=20
idea that you *can't* have a proxy include non-member functions just=20
because you can't have non-member virtual functions is needlessly limited.

*Ensure proper ownership management*
>
> As Mr. Bengt Gustafsson wrote in the mail:
>
> When it comes to lifetime handling I think that Jakob Riedle is right in=
=20
>> that we should strive for getting the same type of semantics as for regu=
lar=20
>> types, as he showed in his code box. I think this means that there must =
be=20
>> some more magic in the proxy code as it will optionally own the data=20
>> itself. The sad part is that now it becomes hard to see how shared_ptr<T=
>=20
>> and shared_ptr<MyProxy> could co-exist pointing to the same T object (T=
=20
>> fulfilling MyProxy of course). But this may be a necessary sacrifice as =
we=20
>> can't support all user written shared pointers out there anyway. Or mayb=
e=20
>> it can be supported (similarly to how a shared_ptr<BASE> can be assigned=
=20
>> from a shared_ptr<DERIVED> and they still share the refcount. This will=
=20
>> require some surgery in the shared_ptr class I suspect. Thinking about t=
he=20
>> details of this will reveal new insights, no doubt.
>>
>
> This is a question I've been thinking about over and over again. On the=
=20
> one hand, if the lifetime issue is coupled with the =E2=80=9Cproxies=E2=
=80=9D, it violates=20
> the single responsibility principle, and it becomes unfriendly to =E2=80=
=9Cstack=20
> objects=E2=80=9D, whose lifetime is controlled by the execution of progra=
m, but it=20
> seems to be easier to use. On the other hand, if the lifetime issue is=20
> decoupled from the =E2=80=9Cproxies=E2=80=9D, users are responsible for m=
anaging the=20
> lifetime, however, they are free to specify the algorithms (for =E2=80=9C=
heap=20
> objects=E2=80=9D, from new/delete to GC).
>
> After some research, I found it unnecessary to couple the lifetime issue=
=20
> with the =E2=80=9Cproxies=E2=80=9D at all, because most situations that r=
equire=20
> polymorphism are implementable without dynamic memory allocation, as the=
=20
> example mentioned earlier demonstrates.
>

Really? Because `std::function` disagrees with you. `std::function` is=20
functionally a proxy for a type that is callable with the `operator()`=20
overload specified by the `function`'s template parameter. And yet, it also=
=20
requires copyable value semantics.

So clearly there is a genuine need for type-erasure+value semantics. Your=
=20
personal use cases may not need it, but if `function` (and `any` for that=
=20
matter) are any indication, combining the two is something people really do=
=20
use.

The way to specify the reference/value semantics for a proxy is pretty=20
easy: use the tools we already have, where possible.

//Value semantics by default
proxy val_proxy
{
};

//Value semantics, move-only.
proxy move_proxy
{
  move_proxy (const move_proxy &) =3D delete;
  move_proxy (move_proxy&&) =3D default;
  move_proxy &operator=3D(const move_proxy &) =3D delete;
  move_proxy &operator=3D(move_proxy&&) =3D default;
};

//Has reference semantics
proxy ref_proxy reference
{
};

For value proxies, we should allow implementations to provide small object=
=20
optimization, just as we permit for `any` and `function`.

Semantics specification *should not* include smart pointers. If a user=20
wants to wrap a smart pointer in such a proxy, then its up to them to do it=
=20
properly. For example, if you have a proxy of some sort, and you have a=20
`shared_ptr<T>` where `T` fulfills the proxy requirements, then the way to=
=20
wrap it is simple: write a type that forwards those requirements and stores=
=20
a `shared_ptr<T>`:

class shared_proxy_T
{
public:
  shared_proxy_T(shared_ptr<T>); //Fill in `t_`.

  //Add proxy requirements, forwarded to `t_`;

private:
  shared_ptr<T> t_;
};

The proxy type used here would need to have value semantics, either copy or=
=20
move (or value semantics, but . If you wanted to proxy a `unique_ptr<T>`,=
=20
then you do the same thing, but it=20

Now, we might have a feature where you could have the compiler generate a=
=20
wrapper given a pointer-like type and a proxy (which specifies what=20
operations to forward). Indeed this could perhaps be done via the proxy map=
=20
feature I suggested, which would allow it to work for *any* `shared_ptr<T>`=
=20
where `T` fits the proxy.

--=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/54105606-cdde-4acf-8232-74c75c3140e3%40isocpp.or=
g.

------=_Part_132_1202200125.1494624482218
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Things your design is potentially lacking (which aren&#39;=
t covered in the meat of my reply):<br><br>Proxies need an equivalent of `d=
ynamic_cast`. Or rather, an equivalent of `any_cast`, which is effectively =
the same thing. You need to be able to extract the type back out of the pro=
xy. And it must be the exact type you provided the proxy.<br><br>Also, I th=
ink we need proxy maps. Remember the old C++11 concepts with concept maps, =
which were basically ways to coerce a type to fit a concept it doesn&#39;t =
really fit? I think this would be <i>very</i> useful for proxies.<br><br>A =
proxy map is a type which implements a particular proxy for a particular gi=
ven type(s), as defined as a template. Consider a callable proxy. That work=
s well enough for class types, but what if you want your callable to be abl=
e to use function pointers or member pointers? You need some kind of class =
type to do the translation there.<br><br>That would be the point of the pro=
xy map. For a given proxy and for a given type (or range of types), you cre=
ate a class. When a user tries to turn one of those types into that class, =
it results in the construction of a proxy map type with that value, which i=
s then passed into the proxy type.<br><br>Unless you can come up with a mor=
e elegant way to handle non-class types, or types that don&#39;t quite fit =
a proxy.<br><br>Basically, my litmus test for proxy design is this: the des=
ign is deficient if you cannot implement `std::function` by using a proxy.<=
br><br>On Friday, May 12, 2017 at 12:41:38 PM UTC-4, Mingxin Wang wrote:<bl=
ockquote 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><span lang=
=3D"EN-US"><font face=3D"georgia, serif">To clarify the motivation and scop=
e, Mr. Bengt Gustafsson and I have discussed about this feature via email y=
esterday. Our opinions and understanding are=C2=A0</font></span><span style=
=3D"font-family:georgia,serif">summarized</span><span style=3D"font-family:=
georgia,serif">=C2=A0as follows.</span></div><div><span lang=3D"EN-US"><fon=
t face=3D"georgia, serif"><br></font></span></div><div><span lang=3D"EN-US"=
><font face=3D"georgia, serif"><font size=3D"4"><b>What do we have now</b><=
/font><br></font></span></div><div><span lang=3D"EN-US"><font face=3D"georg=
ia, serif"><br></font></span></div><div><span lang=3D"EN-US"><div style=3D"=
font-family:georgia,serif">Before the =E2=80=9Cproxies=E2=80=9D, the most w=
idely adopted method to implement polymorphism in C++ is to use virtual fun=
ctions, which exist from the very beginning, and there is little update on =
this feature so far.</div><div style=3D"font-family:georgia,serif"><br></di=
v><div style=3D"font-family:georgia,serif">We used to define base classes w=
ith pure virtual functions, define derived classes inheriting the base, and=
 instantiate derived classes with dynamic memory allocation, as is shown be=
low:</div><div style=3D"font-family:georgia,serif"><br></div><div><div styl=
e=3D"border:1px solid rgb(187,187,187);word-wrap:break-word;background-colo=
r:rgb(250,250,250)"><code><div><font color=3D"#660066"><div>class Base {</d=
iv><div>=C2=A0public:</div><div>=C2=A0 virtual void f() =3D 0;</div><div>=
=C2=A0 virtual int g(double) =3D 0;</div><div>=C2=A0 virtual ~Base() {}</di=
v><div><br></div><div>=C2=A0protected:</div><div>=C2=A0 Base() =3D default;=
</div><div>};</div><div><br></div><div>class Derived : public Base {</div><=
div>=C2=A0public:</div><div>=C2=A0 Derived() =3D default;</div><div>=C2=A0 =
void f() override;</div><div>=C2=A0 int g(double) override;</div><div>};</d=
iv><div><br></div><div>Base* base =3D new Derived();</div><div>base-&gt;f()=
;</div><div>base-&gt;g(3);</div><div>delete base;</div></font></div></code>=
</div><br><font size=3D"4" face=3D"georgia, serif"><b>What is the =E2=80=9C=
proxies=E2=80=9D</b></font><br></div></span></div><div><span lang=3D"EN-US"=
><font face=3D"georgia, serif"><br></font></span></div><div><span lang=3D"E=
N-US"><font face=3D"georgia, serif"><div>It is obvious that dynamic memory =
allocation is harmful to performance, but why are we using it in the code a=
bove? Because, as we are using polymorphism with a uniform base class, the =
implementation for the derived class is completely unknown, including the m=
emory required to construct the derived class (<i>sizeof(Derived)</i>).</di=
v></font></span></div></div></blockquote><div><br>Nobody forced you to allo=
cate memory. You could just as easily have done:<br><br><div style=3D"backg=
round-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-s=
tyle: solid; border-width: 1px; overflow-wrap: break-word;" class=3D"pretty=
print"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span styl=
e=3D"color: #606;" class=3D"styled-by-prettify">Derived</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> d</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">{};</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #606;" cla=
ss=3D"styled-by-prettify">Base</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">*</span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">base</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">d</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #800;" class=3D"st=
yled-by-prettify">//etc.</span></div></code></div><br></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #=
ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><span lang=3D"EN-US"><f=
ont face=3D"georgia, serif"><div></div><div>I have been trying to find out =
whether there is a better solution, and I found it helpful to decouple the =
interfaces (the base classes) and the implementations (the derived classes)=
 with the =E2=80=9Cproxies=E2=80=9D, which is an update version for virtual=
 functions, as is shown below.</div><div><br></div></font></span></div><p s=
tyle=3D"text-align:center;clear:both"><a href=3D"https://lh3.googleusercont=
ent.com/-3m2W7ogUxqE/WRXiIE3hI2I/AAAAAAAAAEY/A72ROREd4pg_fSbuhJ38_D80824FlO=
TbQCLcB/s1600/11.png" style=3D"margin-left:1em;margin-right:1em" target=3D"=
_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D&#39;https://lh3.google=
usercontent.com/-3m2W7ogUxqE/WRXiIE3hI2I/AAAAAAAAAEY/A72ROREd4pg_fSbuhJ38_D=
80824FlOTbQCLcB/s1600/11.png&#39;;return true;" onclick=3D"this.href=3D&#39=
;https://lh3.googleusercontent.com/-3m2W7ogUxqE/WRXiIE3hI2I/AAAAAAAAAEY/A72=
ROREd4pg_fSbuhJ38_D80824FlOTbQCLcB/s1600/11.png&#39;;return true;"><img src=
=3D"https://lh3.googleusercontent.com/-3m2W7ogUxqE/WRXiIE3hI2I/AAAAAAAAAEY/=
A72ROREd4pg_fSbuhJ38_D80824FlOTbQCLcB/s400/11.png" width=3D"400" height=3D"=
216" border=3D"0"></a></p><div><span lang=3D"EN-US"><font face=3D"georgia, =
serif"><br></font></span></div><div><span lang=3D"EN-US"><font face=3D"geor=
gia, serif">The code above can be reconstructed with the =E2=80=9Cproxies=
=E2=80=9D, as is shown below:<br></font></span></div><div><span lang=3D"EN-=
US"><font face=3D"georgia, serif"><br></font></span></div><div><span lang=
=3D"EN-US"><font face=3D"georgia, serif"><div style=3D"border:1px solid rgb=
(187,187,187);word-wrap:break-word;background-color:rgb(250,250,250)"><code=
><div><p class=3D"MsoNormal"><span lang=3D"EN-US">proxy P {</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0
void f();</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0 int
g(double);</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">};</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">class T {</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0public:</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0
void f();</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0 int
g(double);</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">};</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">T t;</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">P p(t);</span></p>

<p class=3D"MsoNormal"><span lang=3D"EN-US">p.f();</span></p>

<span style=3D"font-size:10.0pt;font-family:&quot;Times New Roman&quot;,ser=
if" lang=3D"EN-US">p.g(3);</span><br></div></code></div></font></span><br><=
/div></div></blockquote><blockquote class=3D"gmail_quote" style=3D"margin: =
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div d=
ir=3D"ltr"><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><div>Eve=
rything is so natural! The implementation only need to care about its own s=
emantics ignoring how it corresponds with the requirements (no overriding a=
ny more), and no dynamic memory allocation happens at all!</div></font></sp=
an></div></div></blockquote><div><br>The only difference between that and w=
hat I did up there is that there&#39;s no need to dereference `t` when stor=
ing it in a `p`. If this is intended to be a motivation for proxies, it doe=
sn&#39;t really work.<br><br>A much better motivation for them is, well, pr=
etty much any case for type-erasure (since despite your attempt to call it =
something else, this is clearly language-based type-erasure). One of the ma=
in reasons for type-erasure is to provide polymorphism <i>without</i> being=
 invasive. So it&#39;s about working with types that don&#39;t have base cl=
asses, which you personally do not own and therefore cannot give them base =
classes.<br><br>And equally importantly, types where you don&#39;t <i>want<=
/i> to give them base classes. Like `std::string`.<br><br></div><blockquote=
 class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1=
px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><span lang=3D"EN-US=
"><font face=3D"georgia, serif"><div></div><div>Because the =E2=80=9Cproxie=
s=E2=80=9D is an update version for virtual functions, <b>it can proxy any =
expression that can be declared virtual, including the overloads and operat=
ors, but is not able to proxy the expressions that cannot be declared virtu=
al</b>, e.g. inner types, constructors.</div></font></span></div></div></bl=
ockquote><div><br>No.<br><br>We&#39;re talking about a <i>language feature<=
/i>. You should not limit the behavior of a language feature simply because=
 the analogy no longer fits. If a &quot;proxy&quot; <i>genuinely</i> cannot=
 be implemented which can forward certain constructs, so be it. But you sho=
uldn&#39;t limit the design just to things that can be declared with virtua=
l functions simply because it doesn&#39;t fit into the analogy you built fo=
r it.<br><br>That doesn&#39;t mean we have to do it through concepts, of co=
urse. But the idea that you <i>can&#39;t</i> have a proxy include non-membe=
r functions just because you can&#39;t have non-member virtual functions is=
 needlessly 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><span lang=3D"EN-US"><font face=3D"georgia, ser=
if"></font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, se=
rif"></font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, s=
erif"><font size=3D"4"><b>Ensure proper ownership management</b></font><br>=
</font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, serif"=
><br></font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, s=
erif">As Mr. Bengt Gustafsson wrote in the mail:<br></font></span></div><di=
v><span lang=3D"EN-US"><font face=3D"georgia, serif"><br></font></span></di=
v><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;borde=
r-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204)=
;padding-left:1ex"><span lang=3D"EN-US"><font face=3D"georgia, serif">When =
it comes to lifetime handling I think that Jakob Riedle is right in that we=
 should strive for getting the same type of semantics as for regular types,=
 as he showed in his code box. I think this means that there must be some m=
ore magic in the proxy code as it will optionally own the data itself. The =
sad part is that now it becomes hard to see how shared_ptr&lt;T&gt; and sha=
red_ptr&lt;MyProxy&gt; could co-exist pointing to the same T object (T fulf=
illing MyProxy of course). But this may be a necessary sacrifice as we can&=
#39;t support all user written shared pointers out there anyway. Or maybe i=
t can be supported (similarly to how a shared_ptr&lt;BASE&gt; can be assign=
ed from a shared_ptr&lt;DERIVED&gt; and they still share the refcount. This=
 will require some surgery in the shared_ptr class I suspect. Thinking abou=
t the details of this will reveal new insights, no doubt.<br></font></span>=
</blockquote><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><br></=
font></span></div><div><span lang=3D"EN-US"><div style=3D"font-family:georg=
ia,serif">This is a question I&#39;ve been thinking about over and over aga=
in. On the one hand, if the lifetime issue is coupled with the =E2=80=9Cpro=
xies=E2=80=9D, it violates the single responsibility principle, and it beco=
mes unfriendly to =E2=80=9Cstack objects=E2=80=9D, whose lifetime is contro=
lled by the execution of program, but it seems to be easier to use. On the =
other hand, if the lifetime issue is decoupled from the =E2=80=9Cproxies=E2=
=80=9D, users are responsible for managing the lifetime, however, they are =
free to specify the algorithms (for =E2=80=9Cheap objects=E2=80=9D, from ne=
w/delete to GC).</div><div style=3D"font-family:georgia,serif"><br></div><d=
iv style=3D"font-family:georgia,serif">After some research, I found it unne=
cessary to couple the lifetime issue with the =E2=80=9Cproxies=E2=80=9D at =
all, because most situations that require polymorphism are implementable wi=
thout dynamic memory allocation, as the example mentioned earlier demonstra=
tes.</div></span></div></div></blockquote><div><br>Really? Because `std::fu=
nction` disagrees with you. `std::function` is functionally a proxy for a t=
ype that is callable with the `operator()` overload specified by the `funct=
ion`&#39;s template parameter. And yet, it also requires copyable value sem=
antics.<br><br>So clearly there is a genuine need for type-erasure+value se=
mantics. Your personal use cases may not need it, but if `function` (and `a=
ny` for that matter) are any indication, combining the two is something peo=
ple really do use.<br><br>The way to specify the reference/value semantics =
for a proxy is pretty easy: use the tools we already have, where possible.<=
br><br><div style=3D"background-color: rgb(250, 250, 250); border-color: rg=
b(187, 187, 187); border-style: solid; border-width: 1px; overflow-wrap: br=
eak-word;" class=3D"prettyprint"><code class=3D"prettyprint"><div class=3D"=
subprettyprint"><span style=3D"color: #800;" class=3D"styled-by-prettify">/=
/Value semantics by default</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>proxy val_proxy<br></span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br><br></span><span style=3D"color: #800;" class=3D"styled-by-prett=
ify">//Value semantics, move-only.</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>proxy move_proxy<br></span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br>=C2=A0 move_proxy </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">const</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> move_proxy </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&amp;)</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">=
delete</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 mo=
ve_proxy </span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">move_proxy=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;&amp;=
)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">default</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br>=C2=A0 move_proxy </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">&amp;</span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">operator</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">=3D(</span><span style=3D"color: #008;" c=
lass=3D"styled-by-prettify">const</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> move_proxy </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">&amp;)</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">d=
elete</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 mov=
e_proxy </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&a=
mp;</span><span style=3D"color: #008;" class=3D"styled-by-prettify">operato=
r</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D(</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify">move_proxy</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;&amp;)</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">default</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">};</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br><br></span><span style=3D"color: #800;" class=3D"styled-by-=
prettify">//Has reference semantics</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>proxy ref_proxy reference<br></span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br></span></div></code></div><br>For value proxie=
s, we should allow implementations to provide small object optimization, ju=
st as we permit for `any` and `function`.<br><br>Semantics specification <i=
>should not</i> include smart pointers. If a user wants to wrap a smart poi=
nter in such a proxy, then its up to them to do it properly. For example, i=
f you have a proxy of some sort, and you have a `shared_ptr&lt;T&gt;` where=
 `T` fulfills the proxy requirements, then the way to wrap it is simple: wr=
ite a type that forwards those requirements and stores a `shared_ptr&lt;T&g=
t;`:<br><br><div style=3D"background-color: rgb(250, 250, 250); border-colo=
r: rgb(187, 187, 187); border-style: solid; border-width: 1px; overflow-wra=
p: break-word;" class=3D"prettyprint"><code class=3D"prettyprint"><div clas=
s=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-pretti=
fy">class</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
shared_proxy_T<br></span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">public<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 shared_pr=
oxy_T</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify">shared_ptr</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">T</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&gt;);</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #8=
00;" class=3D"styled-by-prettify">//Fill in `t_`.</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br><br>=C2=A0 </span><span style=3D=
"color: #800;" class=3D"styled-by-prettify">//Add proxy requirements, forwa=
rded to `t_`;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify"=
>private</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =
shared_ptr</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
&lt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">T</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> t_</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">};</span></div></code></div><br>The proxy t=
ype used here would need to have value semantics, either copy or move (or v=
alue semantics, but . If you wanted to proxy a `unique_ptr&lt;T&gt;`, then =
you do the same thing, but it <br><br>Now, we might have a feature where yo=
u could have the compiler generate a wrapper given a pointer-like type and =
a proxy (which specifies what operations to forward). Indeed this could per=
haps be done via the proxy map feature I suggested, which would allow it to=
 work for <i>any</i> `shared_ptr&lt;T&gt;` where `T` fits the proxy.<br></d=
iv></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/54105606-cdde-4acf-8232-74c75c3140e3%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/54105606-cdde-4acf-8232-74c75c3140e3=
%40isocpp.org</a>.<br />

------=_Part_132_1202200125.1494624482218--

------=_Part_131_235314462.1494624482217--

.


Author: Mingxin Wang <wmx16835vv@163.com>
Date: Sat, 13 May 2017 03:21:05 -0700 (PDT)
Raw View
------=_Part_330_1885619690.1494670866110
Content-Type: multipart/alternative;
 boundary="----=_Part_331_749824327.1494670866110"

------=_Part_331_749824327.1494670866110
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable


>
> Things your design is potentially lacking (which aren't covered in the=20
> meat of my reply):
>
> Proxies need an equivalent of `dynamic_cast`. Or rather, an equivalent of=
=20
> `any_cast`, which is effectively the same thing. You need to be able to=
=20
> extract the type back out of the proxy. And it must be the exact type you=
=20
> provided the proxy.
>
> Also, I think we need proxy maps. Remember the old C++11 concepts with=20
> concept maps, which were basically ways to coerce a type to fit a concept=
=20
> it doesn't really fit? I think this would be *very* useful for proxies.
>
> A proxy map is a type which implements a particular proxy for a particula=
r=20
> given type(s), as defined as a template. Consider a callable proxy. That=
=20
> works well enough for class types, but what if you want your callable to =
be=20
> able to use function pointers or member pointers? You need some kind of=
=20
> class type to do the translation there.
>
> A function can be regarded as a const reference to a pointer, so it is OK=
=20
to write the code as shown below:

proxy Runnable {
  void operator()();
};

void fun();

Runnable r(fun);
r();
=20

> That would be the point of the proxy map. For a given proxy and for a=20
> given type (or range of types), you create a class. When a user tries to=
=20
> turn one of those types into that class, it results in the construction o=
f=20
> a proxy map type with that value, which is then passed into the proxy typ=
e.
>
> Unless you can come up with a more elegant way to handle non-class types,=
=20
> or types that don't quite fit a proxy.
>
> Basically, my litmus test for proxy design is this: the design is=20
> deficient if you cannot implement `std::function` by using a proxy.
>
> I think std::function can be replaced by the proxy in many situations wit=
h=20
less type requirements (types are not required to be CopyConstructible) and=
=20
lower runtime overhead (as I roughly tested, *std::function<void()> is=20
approximately 3 times slower to construct than the proxy Runnable* with=20
ordinary function pointers on my PC).

Consider we are to build a threadpool with a queue of tasks (as a buffer),=
=20
and we simply wrap each task into a std::function<void()> (e.g.=20
std::queue<std::function<void()>>), we are unable to submit only=20
MoveConstructible types (e.g. std::packaged_task<void()>) directly.=20
Although it is convenient for users to handle the lifetime issue with=20
std::function<void>, it is much elegant to handle the issue with the=20
support of "Concurrent Invoke" ("Structural Support for C++ Concurrency",=
=20
P0642) because there is only needed to be one concrete implementation for=
=20
each proxy in this situation, and the lifetime can be handled with the flow=
=20
of control, as is shown below:

/* some tasks are defined here*/
auto task_a =3D [] { puts("Lambda"); };
void task_b();
auto task_c =3D [&] { /* do something with "stack objects" */ };

/* Sync Concurrent Invoke */
con::sync_concurrent_invoke([] { puts("Calling thread does nothing but=20
wait"); },
                            /* some concurrent callers that may submit=20
tasks as proxies to some threadpools */);
// Sync Concurrent Invoke will block until all the tasks are done.

The reason why std::function requires the concrete implementation to be=20
CopyConstructible is perhaps that polymorphism is usually accompanied by=20
the use of containers (otherwise, we can use template), and containers=20
often requires the specified types to be CopyConstructible, thus=20
std::function requires the types it wraps to be CopyConstructible.

Because the =E2=80=9Cproxies=E2=80=9D is an update version for virtual func=
tions, *it can=20
>> proxy any expression that can be declared virtual, including the overloa=
ds=20
>> and operators, but is not able to proxy the expressions that cannot be=
=20
>> declared virtual*, e.g. inner types, constructors.
>>
>
> No.
>
> We're talking about a *language feature*. You should not limit the=20
> behavior of a language feature simply because the analogy no longer fits.=
=20
> If a "proxy" *genuinely* cannot be implemented which can forward certain=
=20
> constructs, so be it. But you shouldn't limit the design just to things=
=20
> that can be declared with virtual functions simply because it doesn't fit=
=20
> into the analogy you built for it.
>
> That doesn't mean we have to do it through concepts, of course. But the=
=20
> idea that you *can't* have a proxy include non-member functions just=20
> because you can't have non-member virtual functions is needlessly limited=
..
>
> I wrote this only to limit the expressions that shall appear in a proxy=
=20
definition. Particularly, an expression in the implementation is not=20
necessary to be a member function, it can even be static. It is defined=20
that a proxy can and can only proxy the expressions that are able to be=20
declared virtual, because C++ has done a lot in the virtual function=20
mechanism, and there is enough research in what expressions are suitable=20
for runtime polymorphism.
=20

> *Ensure proper ownership management*
>>
>> As Mr. Bengt Gustafsson wrote in the mail:
>>
>> When it comes to lifetime handling I think that Jakob Riedle is right in=
=20
>>> that we should strive for getting the same type of semantics as for reg=
ular=20
>>> types, as he showed in his code box. I think this means that there must=
 be=20
>>> some more magic in the proxy code as it will optionally own the data=20
>>> itself. The sad part is that now it becomes hard to see how shared_ptr<=
T>=20
>>> and shared_ptr<MyProxy> could co-exist pointing to the same T object (T=
=20
>>> fulfilling MyProxy of course). But this may be a necessary sacrifice as=
 we=20
>>> can't support all user written shared pointers out there anyway. Or may=
be=20
>>> it can be supported (similarly to how a shared_ptr<BASE> can be assigne=
d=20
>>> from a shared_ptr<DERIVED> and they still share the refcount. This will=
=20
>>> require some surgery in the shared_ptr class I suspect. Thinking about =
the=20
>>> details of this will reveal new insights, no doubt.
>>>
>>
>> This is a question I've been thinking about over and over again. On the=
=20
>> one hand, if the lifetime issue is coupled with the =E2=80=9Cproxies=E2=
=80=9D, it violates=20
>> the single responsibility principle, and it becomes unfriendly to =E2=80=
=9Cstack=20
>> objects=E2=80=9D, whose lifetime is controlled by the execution of progr=
am, but it=20
>> seems to be easier to use. On the other hand, if the lifetime issue is=
=20
>> decoupled from the =E2=80=9Cproxies=E2=80=9D, users are responsible for =
managing the=20
>> lifetime, however, they are free to specify the algorithms (for =E2=80=
=9Cheap=20
>> objects=E2=80=9D, from new/delete to GC).
>>
>> After some research, I found it unnecessary to couple the lifetime issue=
=20
>> with the =E2=80=9Cproxies=E2=80=9D at all, because most situations that =
require=20
>> polymorphism are implementable without dynamic memory allocation, as the=
=20
>> example mentioned earlier demonstrates.
>>
>
> Really? Because `std::function` disagrees with you. `std::function` is=20
> functionally a proxy for a type that is callable with the `operator()`=20
> overload specified by the `function`'s template parameter. And yet, it al=
so=20
> requires copyable value semantics.
>
> So clearly there is a genuine need for type-erasure+value semantics. Your=
=20
> personal use cases may not need it, but if `function` (and `any` for that=
=20
> matter) are any indication, combining the two is something people really =
do=20
> use.
>

As you think copying the wrapped object is sometimes necessary, could you=
=20
provide a meaningful use case which is inconvenient to implement with the=
=20
proxy or may reduce runtime overhead while implemented with std::function?

>
> The way to specify the reference/value semantics for a proxy is pretty=20
> easy: use the tools we already have, where possible.
>
> //Value semantics by default
> proxy val_proxy
> {
> };
>
> //Value semantics, move-only.
> proxy move_proxy
> {
>   move_proxy (const move_proxy &) =3D delete;
>   move_proxy (move_proxy&&) =3D default;
>   move_proxy &operator=3D(const move_proxy &) =3D delete;
>   move_proxy &operator=3D(move_proxy&&) =3D default;
> };
>
> //Has reference semantics
> proxy ref_proxy reference
> {
> };
>
> For value proxies, we should allow implementations to provide small objec=
t=20
> optimization, just as we permit for `any` and `function`.
>
> Semantics specification *should not* include smart pointers. If a user=20
> wants to wrap a smart pointer in such a proxy, then its up to them to do =
it=20
> properly. For example, if you have a proxy of some sort, and you have a=
=20
> `shared_ptr<T>` where `T` fulfills the proxy requirements, then the way t=
o=20
> wrap it is simple: write a type that forwards those requirements and stor=
es=20
> a `shared_ptr<T>`:
>
> class shared_proxy_T
> {
> public:
>   shared_proxy_T(shared_ptr<T>); //Fill in `t_`.
>
>   //Add proxy requirements, forwarded to `t_`;
>
> private:
>   shared_ptr<T> t_;
> };
>
> The proxy type used here would need to have value semantics, either copy=
=20
> or move (or value semantics, but . If you wanted to proxy a=20
> `unique_ptr<T>`, then you do the same thing, but it=20
>
> Now, we might have a feature where you could have the compiler generate a=
=20
> wrapper given a pointer-like type and a proxy (which specifies what=20
> operations to forward). Indeed this could perhaps be done via the proxy m=
ap=20
> feature I suggested, which would allow it to work for *any*=20
> `shared_ptr<T>` where `T` fits the proxy.
>

--=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/89115626-5f2e-4c42-bd8e-f2c3341c7d4a%40isocpp.or=
g.

------=_Part_331_749824327.1494670866110
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">Things your d=
esign is potentially lacking (which aren&#39;t covered in the meat of my re=
ply):<br><br>Proxies need an equivalent of `dynamic_cast`. Or rather, an eq=
uivalent of `any_cast`, which is effectively the same thing. You need to be=
 able to extract the type back out of the proxy. And it must be the exact t=
ype you provided the proxy.<br><br>Also, I think we need proxy maps. Rememb=
er the old C++11 concepts with concept maps, which were basically ways to c=
oerce a type to fit a concept it doesn&#39;t really fit? I think this would=
 be <i>very</i> useful for proxies.<br><br>A proxy map is a type which impl=
ements a particular proxy for a particular given type(s), as defined as a t=
emplate. Consider a callable proxy. That works well enough for class types,=
 but what if you want your callable to be able to use function pointers or =
member pointers? You need some kind of class type to do the translation the=
re.<br><br></div></blockquote><div><font face=3D"georgia, serif">A function=
 can be regarded as a const reference to a pointer, so it is OK to write th=
e code as shown below:</font><br></div><div><br></div><div><div class=3D"pr=
ettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-=
word; background-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><d=
iv class=3D"subprettyprint"><font color=3D"#660066"><div class=3D"subpretty=
print">proxy Runnable {</div><div class=3D"subprettyprint">=C2=A0 void oper=
ator()();</div><div class=3D"subprettyprint">};</div><div class=3D"subprett=
yprint"><br></div><div class=3D"subprettyprint">void fun();</div><div class=
=3D"subprettyprint"><br></div><div class=3D"subprettyprint">Runnable r(fun)=
;</div><div class=3D"subprettyprint">r();</div></font></div></code></div></=
div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;m=
argin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr">That would be the point of the proxy map. For a given proxy and fo=
r a given type (or range of types), you create a class. When a user tries t=
o turn one of those types into that class, it results in the construction o=
f a proxy map type with that value, which is then passed into the proxy typ=
e.<br><br>Unless you can come up with a more elegant way to handle non-clas=
s types, or types that don&#39;t quite fit a proxy.<br><br>Basically, my li=
tmus test for proxy design is this: the design is deficient if you cannot i=
mplement `std::function` by using a proxy.<br><br></div></blockquote><div><=
div><font face=3D"georgia, serif">I think std::function can be replaced by =
the proxy in many situations with less type requirements (types are not req=
uired to be CopyConstructible) and lower runtime overhead (as I roughly tes=
ted, <b>std::function&lt;void()&gt; is approximately 3 times slower to cons=
truct than the proxy Runnable</b> with ordinary function pointers on my PC)=
..</font></div><div><font face=3D"georgia, serif"><br></font></div><div><fon=
t face=3D"georgia, serif">Consider we are to build a threadpool with a queu=
e of tasks (as a buffer), and we simply wrap each task into a std::function=
&lt;void()&gt; (e.g. std::queue&lt;std::function&lt;void()&gt;&gt;), we are=
 unable to submit only MoveConstructible types (e.g. std::packaged_task&lt;=
void()&gt;) directly. Although it is convenient for users to handle the lif=
etime issue with std::function&lt;void&gt;, it is much elegant to handle th=
e issue with the support of &quot;Concurrent Invoke&quot; (&quot;Structural=
 Support for C++ Concurrency&quot;, P0642) because there is only needed to =
be one concrete implementation for each proxy in this situation, and the li=
fetime can be handled with the flow of control, as is shown below:</font></=
div></div><div><br></div><div><div class=3D"prettyprint" style=3D"border: 1=
px solid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(2=
50, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><=
font color=3D"#660066"><div class=3D"subprettyprint">/* some tasks are defi=
ned here*/</div><div class=3D"subprettyprint">auto task_a =3D [] { puts(&qu=
ot;Lambda&quot;); };</div><div class=3D"subprettyprint">void task_b();</div=
><div class=3D"subprettyprint">auto task_c =3D [&amp;] { /* do something wi=
th &quot;stack objects&quot; */ };</div><div class=3D"subprettyprint"><br><=
/div><div class=3D"subprettyprint">/* Sync Concurrent Invoke */</div><div c=
lass=3D"subprettyprint">con::sync_concurrent_invoke([] { puts(&quot;Calling=
 thread does nothing but wait&quot;); },<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 /* some =
concurrent callers that may submit tasks as proxies to some threadpools */)=
;</div><div class=3D"subprettyprint">// Sync Concurrent Invoke will block u=
ntil all the tasks are done.</div></font></div></code></div><div><br></div>=
<div><font face=3D"georgia, serif">The reason why std::function requires th=
e concrete implementation to be CopyConstructible is perhaps that polymorph=
ism is usually accompanied by the use of containers (otherwise, we can use =
template), and containers often requires the specified types to be CopyCons=
tructible, thus std::function requires the types it wraps to be CopyConstru=
ctible.</font></div><div><br></div></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div di=
r=3D"ltr"><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><div></di=
v><div>Because the =E2=80=9Cproxies=E2=80=9D is an update version for virtu=
al functions, <b>it can proxy any expression that can be declared virtual, =
including the overloads and operators, but is not able to proxy the express=
ions that cannot be declared virtual</b>, e.g. inner types, constructors.</=
div></font></span></div></div></blockquote><div><br>No.<br><br>We&#39;re ta=
lking about a <i>language feature</i>. You should not limit the behavior of=
 a language feature simply because the analogy no longer fits. If a &quot;p=
roxy&quot; <i>genuinely</i> cannot be implemented which can forward certain=
 constructs, so be it. But you shouldn&#39;t limit the design just to thing=
s that can be declared with virtual functions simply because it doesn&#39;t=
 fit into the analogy you built for it.<br><br>That doesn&#39;t mean we hav=
e to do it through concepts, of course. But the idea that you <i>can&#39;t<=
/i> have a proxy include non-member functions just because you can&#39;t ha=
ve non-member virtual functions is needlessly limited.<br><br></div></div><=
/blockquote><div><font face=3D"georgia, serif">I wrote this only to limit t=
he expressions that shall appear in a proxy definition. Particularly, an ex=
pression in the implementation is not necessary to be a member function, it=
 can even be static. It is defined that a proxy can and can only proxy the =
expressions that are able to be declared virtual, because C++ has done a lo=
t in the virtual function mechanism, and there is enough research in what e=
xpressions are suitable for runtime polymorphism.</font><br></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=
></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8e=
x;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div><span =
lang=3D"EN-US"><font face=3D"georgia, serif"></font></span></div><div><span=
 lang=3D"EN-US"><font face=3D"georgia, serif"></font></span></div><div><spa=
n lang=3D"EN-US"><font face=3D"georgia, serif"><font size=3D"4"><b>Ensure p=
roper ownership management</b></font><br></font></span></div><div><span lan=
g=3D"EN-US"><font face=3D"georgia, serif"><br></font></span></div><div><spa=
n lang=3D"EN-US"><font face=3D"georgia, serif">As Mr. Bengt Gustafsson wrot=
e in the mail:<br></font></span></div><div><span lang=3D"EN-US"><font face=
=3D"georgia, serif"><br></font></span></div><blockquote class=3D"gmail_quot=
e" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-styl=
e:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><span lang=3D"=
EN-US"><font face=3D"georgia, serif">When it comes to lifetime handling I t=
hink that Jakob Riedle is right in that we should strive for getting the sa=
me type of semantics as for regular types, as he showed in his code box. I =
think this means that there must be some more magic in the proxy code as it=
 will optionally own the data itself. The sad part is that now it becomes h=
ard to see how shared_ptr&lt;T&gt; and shared_ptr&lt;MyProxy&gt; could co-e=
xist pointing to the same T object (T fulfilling MyProxy of course). But th=
is may be a necessary sacrifice as we can&#39;t support all user written sh=
ared pointers out there anyway. Or maybe it can be supported (similarly to =
how a shared_ptr&lt;BASE&gt; can be assigned from a shared_ptr&lt;DERIVED&g=
t; and they still share the refcount. This will require some surgery in the=
 shared_ptr class I suspect. Thinking about the details of this will reveal=
 new insights, no doubt.<br></font></span></blockquote><div><span lang=3D"E=
N-US"><font face=3D"georgia, serif"><br></font></span></div><div><span lang=
=3D"EN-US"><div style=3D"font-family:georgia,serif">This is a question I&#3=
9;ve been thinking about over and over again. On the one hand, if the lifet=
ime issue is coupled with the =E2=80=9Cproxies=E2=80=9D, it violates the si=
ngle responsibility principle, and it becomes unfriendly to =E2=80=9Cstack =
objects=E2=80=9D, whose lifetime is controlled by the execution of program,=
 but it seems to be easier to use. On the other hand, if the lifetime issue=
 is decoupled from the =E2=80=9Cproxies=E2=80=9D, users are responsible for=
 managing the lifetime, however, they are free to specify the algorithms (f=
or =E2=80=9Cheap objects=E2=80=9D, from new/delete to GC).</div><div style=
=3D"font-family:georgia,serif"><br></div><div style=3D"font-family:georgia,=
serif">After some research, I found it unnecessary to couple the lifetime i=
ssue with the =E2=80=9Cproxies=E2=80=9D at all, because most situations tha=
t require polymorphism are implementable without dynamic memory allocation,=
 as the example mentioned earlier demonstrates.</div></span></div></div></b=
lockquote><div><br>Really? Because `std::function` disagrees with you. `std=
::function` is functionally a proxy for a type that is callable with the `o=
perator()` overload specified by the `function`&#39;s template parameter. A=
nd yet, it also requires copyable value semantics.<br><br>So clearly there =
is a genuine need for type-erasure+value semantics. Your personal use cases=
 may not need it, but if `function` (and `any` for that matter) are any ind=
ication, combining the two is something people really do use.<br></div></di=
v></blockquote><div><br></div><div><span style=3D"font-family: georgia, ser=
if;">As you think copying the wrapped object is sometimes necessary, could =
you provide a meaningful use case which is inconvenient to implement with t=
he proxy or may reduce runtime overhead while implemented with std::functio=
n?</span></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>The way to specify the reference/value semantics for a proxy is =
pretty easy: use the tools we already have, where possible.<br><br><div sty=
le=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);borde=
r-style:solid;border-width:1px"><code><div><span style=3D"color:#800">//Val=
ue semantics by default</span><span style=3D"color:#000"><br>proxy val_prox=
y<br></span><span style=3D"color:#660">{</span><span style=3D"color:#000"><=
br></span><span style=3D"color:#660">};</span><span style=3D"color:#000"><b=
r><br></span><span style=3D"color:#800">//Value semantics, move-only.</span=
><span style=3D"color:#000"><br>proxy move_proxy<br></span><span style=3D"c=
olor:#660">{</span><span style=3D"color:#000"><br>=C2=A0 move_proxy </span>=
<span style=3D"color:#660">(</span><span style=3D"color:#008">const</span><=
span style=3D"color:#000"> move_proxy </span><span style=3D"color:#660">&am=
p;)</span><span style=3D"color:#000"> </span><span style=3D"color:#660">=3D=
</span><span style=3D"color:#000"> </span><span style=3D"color:#008">delete=
</span><span style=3D"color:#660">;</span><span style=3D"color:#000"><br>=
=C2=A0 move_proxy </span><span style=3D"color:#660">(</span><span style=3D"=
color:#000">move_proxy</span><span style=3D"color:#660">&amp;&amp;)</span><=
span style=3D"color:#000"> </span><span style=3D"color:#660">=3D</span><spa=
n style=3D"color:#000"> </span><span style=3D"color:#008">default</span><sp=
an style=3D"color:#660">;</span><span style=3D"color:#000"><br>=C2=A0 move_=
proxy </span><span style=3D"color:#660">&amp;</span><span style=3D"color:#0=
08">operator</span><span style=3D"color:#660">=3D(</span><span style=3D"col=
or:#008">const</span><span style=3D"color:#000"> move_proxy </span><span st=
yle=3D"color:#660">&amp;)</span><span style=3D"color:#000"> </span><span st=
yle=3D"color:#660">=3D</span><span style=3D"color:#000"> </span><span style=
=3D"color:#008">delete</span><span style=3D"color:#660">;</span><span style=
=3D"color:#000"><br>=C2=A0 move_proxy </span><span style=3D"color:#660">&am=
p;</span><span style=3D"color:#008">operator</span><span style=3D"color:#66=
0">=3D(</span><span style=3D"color:#000">move_proxy</span><span style=3D"co=
lor:#660">&amp;&amp;)</span><span style=3D"color:#000"> </span><span style=
=3D"color:#660">=3D</span><span style=3D"color:#000"> </span><span style=3D=
"color:#008">default</span><span style=3D"color:#660">;</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#660">};</span><span style=
=3D"color:#000"><br><br></span><span style=3D"color:#800">//Has reference s=
emantics</span><span style=3D"color:#000"><br>proxy ref_proxy reference<br>=
</span><span style=3D"color:#660">{</span><span style=3D"color:#000"><br></=
span><span style=3D"color:#660">};</span><span style=3D"color:#000"><br></s=
pan></div></code></div><br>For value proxies, we should allow implementatio=
ns to provide small object optimization, just as we permit for `any` and `f=
unction`.<br><br>Semantics specification <i>should not</i> include smart po=
inters. If a user wants to wrap a smart pointer in such a proxy, then its u=
p to them to do it properly. For example, if you have a proxy of some sort,=
 and you have a `shared_ptr&lt;T&gt;` where `T` fulfills the proxy requirem=
ents, then the way to wrap it is simple: write a type that forwards those r=
equirements and stores a `shared_ptr&lt;T&gt;`:<br><br><div style=3D"backgr=
ound-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:soli=
d;border-width:1px"><code><div><span style=3D"color:#008">class</span><span=
 style=3D"color:#000"> shared_proxy_T<br></span><span style=3D"color:#660">=
{</span><span style=3D"color:#000"><br></span><span style=3D"color:#008">pu=
blic</span><span style=3D"color:#660">:</span><span style=3D"color:#000"><b=
r>=C2=A0 shared_proxy_T</span><span style=3D"color:#660">(</span><span styl=
e=3D"color:#000">shared_ptr</span><span style=3D"color:#660">&lt;</span><sp=
an style=3D"color:#000">T</span><span style=3D"color:#660">&gt;);</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#800">//Fill in `t_`.<=
/span><span style=3D"color:#000"><br><br>=C2=A0 </span><span style=3D"color=
:#800">//Add proxy requirements, forwarded to `t_`;</span><span style=3D"co=
lor:#000"><br><br></span><span style=3D"color:#008">private</span><span sty=
le=3D"color:#660">:</span><span style=3D"color:#000"><br>=C2=A0 shared_ptr<=
/span><span style=3D"color:#660">&lt;</span><span style=3D"color:#000">T</s=
pan><span style=3D"color:#660">&gt;</span><span style=3D"color:#000"> t_</s=
pan><span style=3D"color:#660">;</span><span style=3D"color:#000"><br></spa=
n><span style=3D"color:#660">};</span></div></code></div><br>The proxy type=
 used here would need to have value semantics, either copy or move (or valu=
e semantics, but . If you wanted to proxy a `unique_ptr&lt;T&gt;`, then you=
 do the same thing, but it <br><br>Now, we might have a feature where you c=
ould have the compiler generate a wrapper given a pointer-like type and a p=
roxy (which specifies what operations to forward). Indeed this could perhap=
s be done via the proxy map feature I suggested, which would allow it to wo=
rk for <i>any</i> `shared_ptr&lt;T&gt;` where `T` fits the proxy.<br></div>=
</div></blockquote>

<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/89115626-5f2e-4c42-bd8e-f2c3341c7d4a%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/89115626-5f2e-4c42-bd8e-f2c3341c7d4a=
%40isocpp.org</a>.<br />

------=_Part_331_749824327.1494670866110--

------=_Part_330_1885619690.1494670866110--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sat, 13 May 2017 06:29:14 -0700 (PDT)
Raw View
------=_Part_418_705823553.1494682154594
Content-Type: multipart/alternative;
 boundary="----=_Part_419_922509671.1494682154594"

------=_Part_419_922509671.1494682154594
Content-Type: text/plain; charset="UTF-8"


>
> As you think copying the wrapped object is sometimes necessary, could you
>> provide a meaningful use case which is inconvenient to implement with the
>> proxy or may reduce runtime overhead while implemented with std::function?
>>
>
This would happen often, for instance in a std::vector<MyProxy> which, as
the proxy is by value should own its elements regardless of their actual
types. I think this shows the gist of the ownership problem, because if you
have a std::vector<MyProxy*> then each vector element should be able to
point to any object fulfilling MyProxy. But in this case, where is the
actual proxy object performing the method translation?

I think that the list that Jakob Riedle wrote, and which I copied below
shows the basic idea to start out from. It must be noted that a reference
to a proxy as in "Callable<void()>& c2 = f1;" is not a normal reference,
for what would it refer to? Instead it is a "by reference proxy" which the
compiler understands how to create, thereby allowing different types of
ownership semantics. This only goes so far though, it doesn't solve the
std::vector<MyProxy*> case. Possibly a std::vector<MyProxy&> could be
allowed but this seems odd as containers of references are not allowed in
general.

std::function<void()> f1 = /**/;
> std::function<void()> f2();
>
> const std::function<void()> f3 = /**/;
> Callable<void()> c1 = f1; // This copies f1. Internally, an lvalue object
> of type std::function<void()> is held.
> Callable<void()>& c2 = f1; // This references f1. Internally, an lvalue
> reference (std::function<void()>&) is stored.
> Callable<void()>&& c3 = f2(); // Internally stored as '
> std::function<void()>&&'.
> Callable<void()> c4 = f2(); // This moves the result of f2 into c4.
> Internally stored as real std::function<void()> lvalue .
> const Callable<void()>& c4 = f3; //Internally 'const &' as handle.
> // and so on...
>

 Another thing resulting from this is that this function has a by value
parameter of type 'reference proxy to MyProxy':

void myFunc(MyProxy& s);

This by value object contains a pointer to the actual parameter and a
vtable pointer (or similar) to allow myFunc to call the methods of MyProxy
regardless of the actual parameter type.

This reuse of the & operator clashes with the possibility to create a
reference to a proxy, so if myFunc needs to forward s to a sub-function a
deep copy has to be made (which is just two pointers, but anyway).

Thus it looks as reusing & to indicate proxy ownership is not appropriate
after all, despite the elegance. We need to be able to specify both a
reference to a proxy and a proxy which refers to the actual object.

I would like this to work, but then we must disentangle how concept
contents maps to proxy contents:

concept MyConcept { .... };

class MyClass { ... };      // Class that fulfills MyConcept

MyClass obj;
MyClass& ref = obj;

std::val_proxy<MyConcept> vp = obj;   // Deep copies obj into some internal
or heap storage.
std::ref_proxy<MyConcept> rp = obj;   // Refers to obj.

More importanty:

myRefFun(std::ref_proxy<MyConcept> ra);

myRefFun(obj);    // Refers to obj
myRefFun(rp);      // deep-copies the ref_proxy<MyConcept> rp as expected
myRefFun(vp);     // Creates a ref_proxy from the val_proxy by refering to
the internal copy of obj

std::vector<std::ref_proxy<MyConcept>> myVec;   // This can now be done,
and you can push back references to any complying objects.

The std::ref_proxy and std::val_proxy templates must be magic on the same
level as initializer_list which seems to be a library class template but is
magic. This ducks the issues of having to add keywords or new/reused
operators. It still does not solve the problem of shared ownership between
real and proxy pointers as elegantly as between sub- and baseclass shared
pointers, which brings me back to the original complaint of mine that
ownership and proxying issues should be separated.

What I think we need is a lower level feature which can be used by
std::ref_proxy and std::val_proxy as well as any number of other similar
templates such as shared_proxy and unique_proxy. Something like this:

template<concept C> class ref_proxy {
public:
    template<C S> proxy(S& src) : mObject(&src), c(src) {}

     C(mObject);

private:
     C* mObject;
C c;
};

This introduces concepts as template parameters in order to create a
"higher order template". The first magic happens on the C(mObject) line
which indicates that the mObject pointer is to be used as 'this' in
implementations of all methods requires by C. The second magic is the C*
which is not a normal pointer but a

--
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/7bf7645d-004d-474f-b260-32712bd2e490%40isocpp.org.

------=_Part_419_922509671.1494682154594
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div dir=3D"ltr"><div><div style=3D"background-c=
olor:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;bord=
er-width:1px"><code><div><span style=3D"font-family: georgia, serif; backgr=
ound-color: rgb(255, 255, 255);">As you think copying the wrapped object is=
 sometimes necessary, could you provide a meaningful use case which is inco=
nvenient to implement with the proxy or may reduce runtime overhead while i=
mplemented with std::function?</span></div></code></div></div></div></block=
quote></blockquote><div><br></div><div>This would happen often, for instanc=
e in a std::vector&lt;MyProxy&gt; which, as the proxy is by value should ow=
n its elements regardless of their actual types. I think this shows the gis=
t of the ownership problem, because if you have a std::vector&lt;MyProxy*&g=
t; then each vector element should be able to point to any object fulfillin=
g MyProxy. But in this case, where is the actual proxy object performing th=
e method translation?</div><div><br></div><div>I think that the list that J=
akob Riedle wrote, and which I copied below shows the basic idea to start o=
ut from. It must be noted that a reference to a proxy as in &quot;<span sty=
le=3D"font-family: monospace; background-color: rgb(250, 250, 250); color: =
rgb(102, 0, 102);">Callable</span><span style=3D"font-family: monospace; ba=
ckground-color: rgb(250, 250, 250); color: rgb(102, 102, 0);">&lt;</span><s=
pan style=3D"font-family: monospace; background-color: rgb(250, 250, 250); =
color: rgb(0, 0, 136);">void</span><span style=3D"font-family: monospace; b=
ackground-color: rgb(250, 250, 250); color: rgb(102, 102, 0);">()&gt;&amp;<=
/span><span style=3D"font-family: monospace; background-color: rgb(250, 250=
, 250); color: rgb(0, 0, 0);">=C2=A0c2=C2=A0</span><span style=3D"font-fami=
ly: monospace; background-color: rgb(250, 250, 250); color: rgb(102, 102, 0=
);">=3D</span><span style=3D"font-family: monospace; background-color: rgb(=
250, 250, 250); color: rgb(0, 0, 0);">=C2=A0f1</span><span style=3D"font-fa=
mily: monospace; background-color: rgb(250, 250, 250); color: rgb(102, 102,=
 0);">;&quot;</span>=C2=A0is not a normal reference, for what would it refe=
r to? Instead it is a &quot;by reference proxy&quot; which the compiler und=
erstands how to create, thereby allowing different types of ownership seman=
tics. This only goes so far though, it doesn&#39;t solve the std::vector&lt=
;MyProxy*&gt; case. Possibly a std::vector&lt;MyProxy&amp;&gt; could be all=
owed but this seems odd as containers of references are not allowed in gene=
ral.</div><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:=
 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left=
: 1ex;"><div style=3D"border-width: 1px; border-style: solid; border-color:=
 rgb(187, 187, 187); background-color: rgb(250, 250, 250); word-wrap: break=
-word;"><code><div><span style=3D"color: rgb(0, 0, 0);">std</span><span sty=
le=3D"color: rgb(102, 102, 0);">::</span><span style=3D"color: rgb(0, 0, 13=
6);">function</span><span style=3D"color: rgb(102, 102, 0);">&lt;</span><sp=
an style=3D"color: rgb(0, 0, 136);">void</span><span style=3D"color: rgb(10=
2, 102, 0);">()&gt;</span><span style=3D"color: rgb(0, 0, 0);">=C2=A0f1=C2=
=A0</span><span style=3D"color: rgb(102, 102, 0);">=3D</span><span style=3D=
"color: rgb(0, 0, 0);">=C2=A0</span><span style=3D"color: rgb(136, 0, 0);">=
/**/</span><span style=3D"color: rgb(102, 102, 0);">;</span><span style=3D"=
color: rgb(0, 0, 0);"><br>std</span><span style=3D"color: rgb(102, 102, 0);=
">::</span><span style=3D"color: rgb(0, 0, 136);">function</span><span styl=
e=3D"color: rgb(102, 102, 0);">&lt;</span><span style=3D"color: rgb(0, 0, 1=
36);">void</span><span style=3D"color: rgb(102, 102, 0);">()&gt;</span><spa=
n style=3D"color: rgb(0, 0, 0);">=C2=A0f2</span><span style=3D"color: rgb(1=
02, 102, 0);">();</span><span style=3D"color: rgb(0, 0, 0);"><br><br></span=
><span style=3D"color: rgb(0, 0, 136);">const</span><span style=3D"color: r=
gb(0, 0, 0);">=C2=A0std</span><span style=3D"color: rgb(102, 102, 0);">::</=
span><span style=3D"color: rgb(0, 0, 136);">function</span><span style=3D"c=
olor: rgb(102, 102, 0);">&lt;</span><span style=3D"color: rgb(0, 0, 136);">=
void</span><span style=3D"color: rgb(102, 102, 0);">()&gt;</span><span styl=
e=3D"color: rgb(0, 0, 0);">=C2=A0f3=C2=A0</span><span style=3D"color: rgb(1=
02, 102, 0);">=3D</span><span style=3D"color: rgb(0, 0, 0);">=C2=A0</span><=
span style=3D"color: rgb(136, 0, 0);">/**/</span><span style=3D"color: rgb(=
102, 102, 0);">;</span><span style=3D"color: rgb(0, 0, 0);"><br></span><spa=
n style=3D"color: rgb(102, 0, 102);">Callable</span><span style=3D"color: r=
gb(102, 102, 0);">&lt;</span><span style=3D"color: rgb(0, 0, 136);">void</s=
pan><span style=3D"color: rgb(102, 102, 0);">()&gt;</span><span style=3D"co=
lor: rgb(0, 0, 0);">=C2=A0c1=C2=A0</span><span style=3D"color: rgb(102, 102=
, 0);">=3D</span><span style=3D"color: rgb(0, 0, 0);">=C2=A0f1</span><span =
style=3D"color: rgb(102, 102, 0);">;</span><span style=3D"color: rgb(0, 0, =
0);">=C2=A0</span><span style=3D"color: rgb(136, 0, 0);">// This copies f1.=
 Internally, an lvalue object of type std::function&lt;void()&gt; is held.<=
/span><span style=3D"color: rgb(0, 0, 0);"><br></span><span style=3D"color:=
 rgb(102, 0, 102);">Callable</span><span style=3D"color: rgb(102, 102, 0);"=
>&lt;</span><span style=3D"color: rgb(0, 0, 136);">void</span><span style=
=3D"color: rgb(102, 102, 0);">()&gt;&amp;</span><span style=3D"color: rgb(0=
, 0, 0);">=C2=A0c2=C2=A0</span><span style=3D"color: rgb(102, 102, 0);">=3D=
</span><span style=3D"color: rgb(0, 0, 0);">=C2=A0f1</span><span style=3D"c=
olor: rgb(102, 102, 0);">;</span><span style=3D"color: rgb(0, 0, 0);">=C2=
=A0</span><span style=3D"color: rgb(136, 0, 0);">// This references f1. Int=
ernally, an lvalue reference (std::function&lt;void()&gt;&amp;) is stored.<=
/span><span style=3D"color: rgb(0, 0, 0);"><br></span><span style=3D"color:=
 rgb(102, 0, 102);">Callable</span><span style=3D"color: rgb(102, 102, 0);"=
>&lt;</span><span style=3D"color: rgb(0, 0, 136);">void</span><span style=
=3D"color: rgb(102, 102, 0);">()&gt;&amp;&amp;</span><span style=3D"color: =
rgb(0, 0, 0);">=C2=A0c3=C2=A0</span><span style=3D"color: rgb(102, 102, 0);=
">=3D</span><span style=3D"color: rgb(0, 0, 0);">=C2=A0f2</span><span style=
=3D"color: rgb(102, 102, 0);">();</span><span style=3D"color: rgb(0, 0, 0);=
">=C2=A0</span><span style=3D"color: rgb(136, 0, 0);">// Internally stored =
as &#39;</span><span style=3D"color: rgb(136, 0, 0); font-family: Arial, He=
lvetica, sans-serif;">std::function&lt;void()&gt;</span><span style=3D"colo=
r: rgb(136, 0, 0); font-family: Arial, Helvetica, sans-serif;">&amp;&amp;&#=
39;.</span></div><div><span style=3D"color: rgb(102, 0, 102);">Callable</sp=
an><span style=3D"color: rgb(102, 102, 0);">&lt;</span><span style=3D"color=
: rgb(0, 0, 136);">void</span><span style=3D"color: rgb(102, 102, 0);">()&g=
t;</span><span style=3D"color: rgb(0, 0, 0);">=C2=A0c4=C2=A0</span><span st=
yle=3D"color: rgb(102, 102, 0);">=3D</span><span style=3D"color: rgb(0, 0, =
0);">=C2=A0f2</span><span style=3D"color: rgb(102, 102, 0);">();</span><spa=
n style=3D"color: rgb(0, 0, 0);">=C2=A0</span><span style=3D"color: rgb(136=
, 0, 0);">// This moves the result of f2 into c4. Internally stored as real=
=C2=A0</span><span style=3D"color: rgb(136, 0, 0); font-family: Arial, Helv=
etica, sans-serif;">std::function&lt;void()&gt;=C2=A0</span><span style=3D"=
font-family: Arial, Helvetica, sans-serif; color: rgb(136, 0, 0);">lva<wbr>=
lue=C2=A0</span><span style=3D"font-family: Arial, Helvetica, sans-serif; c=
olor: rgb(136, 0, 0);">.</span></div><div><span style=3D"color: rgb(0, 0, 1=
36);">const</span><span style=3D"color: rgb(0, 0, 0);">=C2=A0</span><span s=
tyle=3D"color: rgb(102, 0, 102);">Callable</span><span style=3D"color: rgb(=
102, 102, 0);">&lt;</span><span style=3D"color: rgb(0, 0, 136);">void</span=
><span style=3D"color: rgb(102, 102, 0);">()&gt;&amp;</span><span style=3D"=
color: rgb(0, 0, 0);">=C2=A0c4=C2=A0</span><span style=3D"color: rgb(102, 1=
02, 0);">=3D</span><span style=3D"color: rgb(0, 0, 0);">=C2=A0f3</span><spa=
n style=3D"color: rgb(102, 102, 0);">;</span><span style=3D"color: rgb(0, 0=
, 0);">=C2=A0</span><span style=3D"color: rgb(136, 0, 0);">//Internally &#3=
9;const &amp;&#39; as handle.</span><span style=3D"color: rgb(0, 0, 0);"><b=
r></span><span style=3D"color: rgb(136, 0, 0);">// and so on...</span></div=
></code></div></blockquote><div><br></div><div>=C2=A0Another thing resultin=
g from this is that this function has a by value parameter of type &#39;ref=
erence proxy to MyProxy&#39;:</div><div><br></div><div>void myFunc(MyProxy&=
amp; s);</div><div><br></div><div>This by value object contains a pointer t=
o the actual parameter and a vtable pointer (or similar) to allow myFunc to=
 call the methods of MyProxy regardless of the actual parameter type.</div>=
<div><br></div><div>This reuse of the &amp; operator clashes with the possi=
bility to create a reference to a proxy, so if myFunc needs to forward s to=
 a sub-function a deep copy has to be made (which is just two pointers, but=
 anyway).</div><div><br></div><div>Thus it looks as reusing &amp; to indica=
te proxy ownership is not appropriate after all, despite the elegance. We n=
eed to be able to specify both a reference to a proxy and a proxy which ref=
ers to the actual object.</div><div><br></div><div>I would like this to wor=
k, but then we must disentangle how concept contents maps to proxy contents=
:</div><div><br></div><div>concept MyConcept { .... };</div><div><br></div>=
<div>class MyClass { ... }; =C2=A0 =C2=A0 =C2=A0// Class that fulfills MyCo=
ncept</div><div><br></div><div>MyClass obj;</div><div>MyClass&amp; ref =3D =
obj;</div><div><br></div><div>std::val_proxy&lt;MyConcept&gt; vp =3D obj; =
=C2=A0 // Deep copies obj into some internal or heap storage.</div><div>std=
::ref_proxy&lt;MyConcept&gt; rp =3D obj; =C2=A0 // Refers to obj.</div><div=
><br></div><div>More importanty:</div><div><br></div><div>myRefFun(std::ref=
_proxy&lt;MyConcept&gt; ra);</div><div><br></div><div>myRefFun(obj); =C2=A0=
 =C2=A0// Refers to obj</div><div>myRefFun(rp); =C2=A0 =C2=A0 =C2=A0// deep=
-copies the ref_proxy&lt;MyConcept&gt; rp as expected</div><div>myRefFun(vp=
); =C2=A0 =C2=A0 // Creates a ref_proxy from the val_proxy by refering to t=
he internal copy of obj</div><div><br></div><div>std::vector&lt;std::ref_pr=
oxy&lt;MyConcept&gt;&gt; myVec; =C2=A0 // This can now be done, and you can=
 push back references to any complying objects.</div><div><br></div><div>Th=
e std::ref_proxy and std::val_proxy templates must be magic on the same lev=
el as initializer_list which seems to be a library class template but is ma=
gic. This ducks the issues of having to add keywords or new/reused operator=
s. It still does not solve the problem of shared ownership between real and=
 proxy pointers as elegantly as between sub- and baseclass shared pointers,=
 which brings me back to the original complaint of mine that ownership and =
proxying issues should be separated.</div><div><br></div><div>What I think =
we need is a lower level feature which can be used by std::ref_proxy and st=
d::val_proxy as well as any number of other similar templates such as share=
d_proxy and unique_proxy. Something like this:</div><div><br></div><div>tem=
plate&lt;concept C&gt; class ref_proxy {</div><div>public:</div><div>=C2=A0=
 =C2=A0 template&lt;C S&gt; proxy(S&amp; src) : mObject(&amp;src), c(src) {=
}</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0C(mObject);</div><div><br></=
div><div>private:</div><div>=C2=A0 =C2=A0 =C2=A0C* mObject;=C2=A0</div><div=
>C c;</div><div>};</div><div><br></div><div>This introduces concepts as tem=
plate parameters in order to create a &quot;higher order template&quot;. Th=
e first magic happens on the C(mObject) line which indicates that the mObje=
ct pointer is to be used as &#39;this&#39; in implementations of all method=
s requires by C. The second magic is the C* which is not a normal pointer b=
ut a=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/7bf7645d-004d-474f-b260-32712bd2e490%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/7bf7645d-004d-474f-b260-32712bd2e490=
%40isocpp.org</a>.<br />

------=_Part_419_922509671.1494682154594--

------=_Part_418_705823553.1494682154594--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sat, 13 May 2017 06:42:22 -0700 (PDT)
Raw View
------=_Part_365_2117364570.1494682942944
Content-Type: multipart/alternative;
 boundary="----=_Part_366_386796099.1494682942944"

------=_Part_366_386796099.1494682942944
Content-Type: text/plain; charset="UTF-8"

Sorry, that got sent a bit too early... let me complete the last part as
best I can:


What I think we need is a lower level feature which can be used by
std::ref_proxy and std::val_proxy as well as any number of other similar
templates such as shared_proxy and unique_proxy. Something like this:

template<concept C> class ref_proxy {
public:
    template<C S> proxy(S& src) : mObject(&src), c(src) {}

     c(mObject);

private:
     void* mObject;
     C c;
};

This introduces concepts as template parameters in order to create a
"higher order template". The first magic happens on the c(mObject) line
which indicates that the mObject pointer is to be used as 'this' in
implementations of all methods requires by C. The second magic is the C c;
and its initialization from src. What this means is that a by value concept
object in a template<concept> class contains the vtable pointer and
initiates it in the template ctor.

I think it is pretty obvious that val_proxy (with or without SOO) as well
as shared_proxy etc. can be implemented similarly.

This idea was just a result of trying to de-construct the proposed "proxy"
idea to find the most basic "magic feature" possible. Just view this as a
starting point for a discussion if and how concepts as template parameters
can be used to implement proxies, but also if there are other uses for this
feature, how this feature actually works and how the c(mObject) line would
be more appropriately expressed syntactically.

--
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/ea97f8c7-8d2e-4bcf-b694-5198da00c449%40isocpp.org.

------=_Part_366_386796099.1494682942944
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Sorry, that got sent a bit too early... let me complete th=
e last part as best I can:<div><div><br></div><div><br></div><div>What I th=
ink we need is a lower level feature which can be used by std::ref_proxy an=
d std::val_proxy as well as any number of other similar templates such as s=
hared_proxy and unique_proxy. Something like this:</div><div><br></div><div=
>template&lt;concept C&gt; class ref_proxy {</div><div>public:</div><div>=
=C2=A0 =C2=A0 template&lt;C S&gt; proxy(S&amp; src) : mObject(&amp;src), c(=
src) {}</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0c(mObject);</div><div>=
<br></div><div>private:</div><div>=C2=A0 =C2=A0 =C2=A0void* mObject;=C2=A0<=
/div><div>=C2=A0 =C2=A0 =C2=A0C c;</div><div>};</div><div><br></div><div>Th=
is introduces concepts as template parameters in order to create a &quot;hi=
gher order template&quot;. The first magic happens on the c(mObject) line w=
hich indicates that the mObject pointer is to be used as &#39;this&#39; in =
implementations of all methods requires by C. The second magic is the C c; =
and its initialization from src. What this means is that a by value concept=
 object in a template&lt;concept&gt; class contains the vtable pointer and =
initiates it in the template ctor.</div><div><br></div><div>I think it is p=
retty obvious that val_proxy (with or without SOO) as well as shared_proxy =
etc. can be implemented similarly.</div><div><br></div><div>This idea was j=
ust a result of trying to de-construct the proposed &quot;proxy&quot; idea =
to find the most basic &quot;magic feature&quot; possible. Just view this a=
s a starting point for a discussion if and how concepts as template paramet=
ers can be used to implement proxies, but also if there are other uses for =
this feature, how this feature actually works and how the c(mObject) line w=
ould be more appropriately expressed syntactically.</div></div></div>

<p></p>

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

------=_Part_366_386796099.1494682942944--

------=_Part_365_2117364570.1494682942944--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 13 May 2017 09:11:40 -0700 (PDT)
Raw View
------=_Part_566_1163057103.1494691900227
Content-Type: multipart/alternative;
 boundary="----=_Part_567_1293647777.1494691900227"

------=_Part_567_1293647777.1494691900227
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Saturday, May 13, 2017 at 6:21:06 AM UTC-4, Mingxin Wang wrote:
>
> Things your design is potentially lacking (which aren't covered in the=20
>> meat of my reply):
>>
>> Proxies need an equivalent of `dynamic_cast`. Or rather, an equivalent o=
f=20
>> `any_cast`, which is effectively the same thing. You need to be able to=
=20
>> extract the type back out of the proxy. And it must be the exact type yo=
u=20
>> provided the proxy.
>>
>> Also, I think we need proxy maps. Remember the old C++11 concepts with=
=20
>> concept maps, which were basically ways to coerce a type to fit a concep=
t=20
>> it doesn't really fit? I think this would be *very* useful for proxies.
>>
>> A proxy map is a type which implements a particular proxy for a=20
>> particular given type(s), as defined as a template. Consider a callable=
=20
>> proxy. That works well enough for class types, but what if you want your=
=20
>> callable to be able to use function pointers or member pointers? You nee=
d=20
>> some kind of class type to do the translation there.
>>
>> A function can be regarded as a const reference to a pointer, so it is O=
K=20
> to write the code as shown below:
>
> proxy Runnable {
>   void operator()();
> };
>
> void fun();
>
> Runnable r(fun);
> r();
>

And member pointers?

That would be the point of the proxy map. For a given proxy and for a given=
=20
>> type (or range of types), you create a class. When a user tries to turn =
one=20
>> of those types into that class, it results in the construction of a prox=
y=20
>> map type with that value, which is then passed into the proxy type.
>>
>> Unless you can come up with a more elegant way to handle non-class types=
,=20
>> or types that don't quite fit a proxy.
>>
>> Basically, my litmus test for proxy design is this: the design is=20
>> deficient if you cannot implement `std::function` by using a proxy.
>>
>> I think std::function can be replaced by the proxy in many situations=20
> with less type requirements (types are not required to be=20
> CopyConstructible) and lower runtime overhead (as I roughly tested, *std:=
:function<void()>=20
> is approximately 3 times slower to construct than the proxy Runnable*=20
> with ordinary function pointers on my PC).
>

What If I *want* a CopyConstructible proxy? I'm not saying reference=20
proxies are bad; I'm saying that the idea of type-erased classes should not=
=20
simultaneously *require* that they only store references.

Consider the member function issue. You say that your `Runnable` proxy=20
should be able to work with a fundamental type like function pointers. But=
=20
it can't work with member functions, since those require some form of=20
intermediary to convert the funky .*() call syntax into regular operator()=
=20
syntax.

So what happens if you try to do this:

Runnable func(std::mem_fn(&Typename::MemFunc));

That's putting a temporary into a reference type. That doesn't work very=20
well.

Now yes, we would *all* like to just make member pointers callable with ()=
=20
like regular function pointers. But sadly, the committee rejected that=20
for... reasons. So we have to make due with the language we've got.

But don't think that the utility of this kind of intermediate object tool=
=20
ends with member pointers. There are many cases where you have some type=20
that *almost* fulfills an interface. The way to deal with that is to make a=
=20
wrapper of some kind to fill in the gaps. And wrappers will generally=20
created as needed through temporaries (like `std::mem_fn`), rather than=20
used directly.

Type-erased objects are very useful for many things. But limiting them to=
=20
references to the type-erased object limits your ability to do things like=
=20
the above. Where you create a type to act as an intermediary to fill in an=
=20
interface that doesn't quite fit the proxy's definition.

As to what efficiencies can be gained by allowing the compiler to generate=
=20
value semantics proxies, that depends on the cleverness of compiler=20
vendors. The thing I'd be most interested in is the possibility for=20
allowing the user to specify allocators that also get type-erased.=20
`std::function` used to have constructors that took allocators, but they=20
were fundamentally unworkable and were removed. But compilers can do all=20
kinds of things that we can't; they might be able to implement type-erased=
=20
allocators for value proxies even when we can't.

The reason why std::function requires the concrete implementation to be=20
> CopyConstructible is perhaps that polymorphism is usually accompanied by=
=20
> the use of containers (otherwise, we can use template), and containers=20
> often requires the specified types to be CopyConstructible, thus=20
> std::function requires the types it wraps to be CopyConstructible.
>

Um, no. The reason why `std::function` uses value semantics is because it=
=20
makes code like the above `Runnable` example actually *work*. It allows you=
=20
to use `mem_fn`, `bind`, lambda expressions, and all kinds of other things=
=20
that you could never use with reference semantics callables.

Because the =E2=80=9Cproxies=E2=80=9D is an update version for virtual func=
tions, *it can=20
>>> proxy any expression that can be declared virtual, including the overlo=
ads=20
>>> and operators, but is not able to proxy the expressions that cannot be=
=20
>>> declared virtual*, e.g. inner types, constructors.
>>>
>>
>> No.
>>
>> We're talking about a *language feature*. You should not limit the=20
>> behavior of a language feature simply because the analogy no longer fits=
..=20
>> If a "proxy" *genuinely* cannot be implemented which can forward certain=
=20
>> constructs, so be it. But you shouldn't limit the design just to things=
=20
>> that can be declared with virtual functions simply because it doesn't fi=
t=20
>> into the analogy you built for it.
>>
>> That doesn't mean we have to do it through concepts, of course. But the=
=20
>> idea that you *can't* have a proxy include non-member functions just=20
>> because you can't have non-member virtual functions is needlessly limite=
d.
>>
>> I wrote this only to limit the expressions that shall appear in a proxy=
=20
> definition. Particularly, an expression in the implementation is not=20
> necessary to be a member function, it can even be static. It is defined=
=20
> that a proxy can and can only proxy the expressions that are able to be=
=20
> declared virtual, because C++ has done a lot in the virtual function=20
> mechanism, and there is enough research in what expressions are suitable=
=20
> for runtime polymorphism.
>

But "expressions" cannot be "declared virtual"; *member functions* are=20
declared virtual. Therefore, if we translate what you said into=20
standardese, the only conclusion is that the only things that can appear in=
=20
a proxy definition are member functions.

If that's not the intent, then please be more clear as to exactly what can=
=20
appear in a proxy definition.

*Ensure proper ownership management*
>>>
>>> As Mr. Bengt Gustafsson wrote in the mail:
>>>
>>> When it comes to lifetime handling I think that Jakob Riedle is right i=
n=20
>>>> that we should strive for getting the same type of semantics as for re=
gular=20
>>>> types, as he showed in his code box. I think this means that there mus=
t be=20
>>>> some more magic in the proxy code as it will optionally own the data=
=20
>>>> itself. The sad part is that now it becomes hard to see how shared_ptr=
<T>=20
>>>> and shared_ptr<MyProxy> could co-exist pointing to the same T object (=
T=20
>>>> fulfilling MyProxy of course). But this may be a necessary sacrifice a=
s we=20
>>>> can't support all user written shared pointers out there anyway. Or ma=
ybe=20
>>>> it can be supported (similarly to how a shared_ptr<BASE> can be assign=
ed=20
>>>> from a shared_ptr<DERIVED> and they still share the refcount. This wil=
l=20
>>>> require some surgery in the shared_ptr class I suspect. Thinking about=
 the=20
>>>> details of this will reveal new insights, no doubt.
>>>>
>>>
>>> This is a question I've been thinking about over and over again. On the=
=20
>>> one hand, if the lifetime issue is coupled with the =E2=80=9Cproxies=E2=
=80=9D, it violates=20
>>> the single responsibility principle, and it becomes unfriendly to =E2=
=80=9Cstack=20
>>> objects=E2=80=9D, whose lifetime is controlled by the execution of prog=
ram, but it=20
>>> seems to be easier to use. On the other hand, if the lifetime issue is=
=20
>>> decoupled from the =E2=80=9Cproxies=E2=80=9D, users are responsible for=
 managing the=20
>>> lifetime, however, they are free to specify the algorithms (for =E2=80=
=9Cheap=20
>>> objects=E2=80=9D, from new/delete to GC).
>>>
>>> After some research, I found it unnecessary to couple the lifetime issu=
e=20
>>> with the =E2=80=9Cproxies=E2=80=9D at all, because most situations that=
 require=20
>>> polymorphism are implementable without dynamic memory allocation, as th=
e=20
>>> example mentioned earlier demonstrates.
>>>
>>
>> Really? Because `std::function` disagrees with you. `std::function` is=
=20
>> functionally a proxy for a type that is callable with the `operator()`=
=20
>> overload specified by the `function`'s template parameter. And yet, it a=
lso=20
>> requires copyable value semantics.
>>
>> So clearly there is a genuine need for type-erasure+value semantics. You=
r=20
>> personal use cases may not need it, but if `function` (and `any` for tha=
t=20
>> matter) are any indication, combining the two is something people really=
 do=20
>> use.
>>
>
> As you think copying the wrapped object is sometimes necessary, could you=
=20
> provide a meaningful use case which is inconvenient to implement with the=
=20
> proxy or may reduce runtime overhead while implemented with std::function=
?
>

OK, let's say you want to use a reference proxy to implement a copyable=20
value proxy. To do that, you have to store the reference proxy, which is=20
going to take up (at least) a pointer of storage. You also need to store=20
sufficient space for your own pointer to your own type-erased allocated=20
object (possibly with small storage optimization). You can't use the=20
proxy's storage because you don't know the type to extract from the proxy=
=20
in order to delete it. So you need to store your own type-erasure machinery=
=20
to do the actual deleting.

So a `std::function` implemented in terms of a reference proxy would be=20
less efficient than `std::function` implemented by itself. As would any=20
other value-semantics type implemented around a reference.

--=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/332280b7-e28d-494b-bd09-dc07ecd3baa8%40isocpp.or=
g.

------=_Part_567_1293647777.1494691900227
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Saturday, May 13, 2017 at 6:21:06 AM UTC-4, Mingxin Wan=
g wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><blockquote class=3D"g=
mail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;=
padding-left:1ex"><div dir=3D"ltr">Things your design is potentially lackin=
g (which aren&#39;t covered in the meat of my reply):<br><br>Proxies need a=
n equivalent of `dynamic_cast`. Or rather, an equivalent of `any_cast`, whi=
ch is effectively the same thing. You need to be able to extract the type b=
ack out of the proxy. And it must be the exact type you provided the proxy.=
<br><br>Also, I think we need proxy maps. Remember the old C++11 concepts w=
ith concept maps, which were basically ways to coerce a type to fit a conce=
pt it doesn&#39;t really fit? I think this would be <i>very</i> useful for =
proxies.<br><br>A proxy map is a type which implements a particular proxy f=
or a particular given type(s), as defined as a template. Consider a callabl=
e proxy. That works well enough for class types, but what if you want your =
callable to be able to use function pointers or member pointers? You need s=
ome kind of class type to do the translation there.<br><br></div></blockquo=
te><div><font face=3D"georgia, serif">A function can be regarded as a const=
 reference to a pointer, so it is OK to write the code as shown below:</fon=
t><br></div><div><br></div><div><div style=3D"border:1px solid rgb(187,187,=
187);word-wrap:break-word;background-color:rgb(250,250,250)"><code><div><fo=
nt color=3D"#660066"><div>proxy Runnable {</div><div>=C2=A0 void operator()=
();</div><div>};</div><div><br></div><div>void fun();</div><div><br></div><=
div>Runnable r(fun);</div><div>r();</div></font></div></code></div></div></=
blockquote><div><br>And member pointers?<br><br></div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;"><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">That would be the point of the proxy map. For a given proxy and for a=
 given type (or range of types), you create a class. When a user tries to t=
urn one of those types into that class, it results in the construction of a=
 proxy map type with that value, which is then passed into the proxy type.<=
br><br>Unless you can come up with a more elegant way to handle non-class t=
ypes, or types that don&#39;t quite fit a proxy.<br><br>Basically, my litmu=
s test for proxy design is this: the design is deficient if you cannot impl=
ement `std::function` by using a proxy.<br><br></div></blockquote><div><div=
><font face=3D"georgia, serif">I think std::function can be replaced by the=
 proxy in many situations with less type requirements (types are not requir=
ed to be CopyConstructible) and lower runtime overhead (as I roughly tested=
, <b>std::function&lt;void()&gt; is approximately 3 times slower to constru=
ct than the proxy Runnable</b> with ordinary function pointers on my PC).</=
font></div></div></blockquote><div><br>What If I <i>want</i> a CopyConstruc=
tible proxy? I&#39;m not saying reference proxies are bad; I&#39;m saying t=
hat the idea of type-erased classes should not simultaneously <i>require</i=
> that they only store references.<br><br>Consider the member function issu=
e. You say that your `Runnable` proxy should be able to work with a fundame=
ntal type like function pointers. But it can&#39;t work with member functio=
ns, since those require some form of intermediary to convert the funky .*()=
 call syntax into regular operator() syntax.<br><br>So what happens if you =
try to do this:<br><br><div style=3D"background-color: rgb(250, 250, 250); =
border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; o=
verflow-wrap: break-word;" class=3D"prettyprint"><code class=3D"prettyprint=
"><div class=3D"subprettyprint"><span style=3D"color: #606;" class=3D"style=
d-by-prettify">Runnable</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> func</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">s=
td</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">mem_fn</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">(&amp;</span><span s=
tyle=3D"color: #606;" class=3D"styled-by-prettify">Typename</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"co=
lor: #606;" class=3D"styled-by-prettify">MemFunc</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">));</span></div></code></div><br>That=
&#39;s putting a temporary into a reference type. That doesn&#39;t work ver=
y well.<br><br>Now yes, we would <i>all</i> like to just make member pointe=
rs callable=20
with () like regular function pointers. But sadly, the committee=20
rejected that for... reasons. So we have to make due with the language=20
we&#39;ve got.<br><br>But don&#39;t think that the utility of this kind of =
intermediate object tool ends with member pointers. There are many cases wh=
ere you have some type that <i>almost</i> fulfills an interface. The way to=
 deal with that is to make a wrapper of some kind to fill in the gaps. And =
wrappers will generally created as needed through temporaries (like `std::m=
em_fn`), rather than used directly.<br><br>Type-erased objects are very use=
ful for many things. But limiting them=20
to references to the type-erased object limits your ability to do things
 like the above. Where you create a type to act as an intermediary to fill =
in an interface that doesn&#39;t quite fit the proxy&#39;s definition.<br><=
br>As to what efficiencies can be gained by allowing the compiler to genera=
te value semantics proxies, that depends on the cleverness of compiler vend=
ors. The thing I&#39;d be most interested in is the possibility for allowin=
g the user to specify allocators that also get type-erased. `std::function`=
 used to have constructors that took allocators, but they were fundamentall=
y unworkable and were removed. But compilers can do all kinds of things tha=
t we can&#39;t; they might be able to implement type-erased allocators for =
value proxies even when we can&#39;t.<br><br></div><blockquote class=3D"gma=
il_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid=
;padding-left: 1ex;"><div><div><font face=3D"georgia, serif">The reason why=
 std::function requires the concrete implementation to be CopyConstructible=
 is perhaps that polymorphism is usually accompanied by the use of containe=
rs (otherwise, we can use template), and containers often requires the spec=
ified types to be CopyConstructible, thus std::function requires the types =
it wraps to be CopyConstructible.</font></div></div></blockquote><div><br>U=
m, no. The reason why `std::function` uses value semantics is because it ma=
kes code like the above `Runnable` example actually <i>work</i>. It allows =
you to use `mem_fn`, `bind`, lambda expressions, and all kinds of other thi=
ngs that you could never use with reference semantics callables.<br><br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><div><div></div></div><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"><blockquote class=3D"gm=
ail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;p=
adding-left:1ex"><div dir=3D"ltr"><div><span lang=3D"EN-US"><font face=3D"g=
eorgia, serif"><div></div><div>Because the =E2=80=9Cproxies=E2=80=9D is an =
update version for virtual functions, <b>it can proxy any expression that c=
an be declared virtual, including the overloads and operators, but is not a=
ble to proxy the expressions that cannot be declared virtual</b>, e.g. inne=
r types, constructors.</div></font></span></div></div></blockquote><div><br=
>No.<br><br>We&#39;re talking about a <i>language feature</i>. You should n=
ot limit the behavior of a language feature simply because the analogy no l=
onger fits. If a &quot;proxy&quot; <i>genuinely</i> cannot be implemented w=
hich can forward certain constructs, so be it. But you shouldn&#39;t limit =
the design just to things that can be declared with virtual functions simpl=
y because it doesn&#39;t fit into the analogy you built for it.<br><br>That=
 doesn&#39;t mean we have to do it through concepts, of course. But the ide=
a that you <i>can&#39;t</i> have a proxy include non-member functions just =
because you can&#39;t have non-member virtual functions is needlessly limit=
ed.<br><br></div></div></blockquote><div><font face=3D"georgia, serif">I wr=
ote this only to limit the expressions that shall appear in a proxy definit=
ion. Particularly, an expression in the implementation is not necessary to =
be a member function, it can even be static. It is defined that a proxy can=
 and can only proxy the expressions that are able to be declared virtual, b=
ecause C++ has done a lot in the virtual function mechanism, and there is e=
nough research in what expressions are suitable for runtime polymorphism.</=
font></div></blockquote><div><br>But &quot;expressions&quot; cannot be &quo=
t;declared virtual&quot;; <i>member functions</i> are declared virtual. The=
refore, if we translate what you said into standardese, the only conclusion=
 is that the only things that can appear in a proxy definition are member f=
unctions.<br><br>If that&#39;s not the intent, then please be more clear as=
 to exactly what can appear in a proxy definition.<br><br></div><blockquote=
 class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1=
px #ccc solid;padding-left: 1ex;"><div></div><blockquote class=3D"gmail_quo=
te" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-=
left:1ex"><div dir=3D"ltr"><div></div><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1e=
x"><div dir=3D"ltr"><div><span lang=3D"EN-US"><font face=3D"georgia, serif"=
></font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, serif=
"></font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, seri=
f"><font size=3D"4"><b>Ensure proper ownership management</b></font><br></f=
ont></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><b=
r></font></span></div><div><span lang=3D"EN-US"><font face=3D"georgia, seri=
f">As Mr. Bengt Gustafsson wrote in the mail:<br></font></span></div><div><=
span lang=3D"EN-US"><font face=3D"georgia, serif"><br></font></span></div><=
blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l=
eft-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);pa=
dding-left:1ex"><span lang=3D"EN-US"><font face=3D"georgia, serif">When it =
comes to lifetime handling I think that Jakob Riedle is right in that we sh=
ould strive for getting the same type of semantics as for regular types, as=
 he showed in his code box. I think this means that there must be some more=
 magic in the proxy code as it will optionally own the data itself. The sad=
 part is that now it becomes hard to see how shared_ptr&lt;T&gt; and shared=
_ptr&lt;MyProxy&gt; could co-exist pointing to the same T object (T fulfill=
ing MyProxy of course). But this may be a necessary sacrifice as we can&#39=
;t support all user written shared pointers out there anyway. Or maybe it c=
an be supported (similarly to how a shared_ptr&lt;BASE&gt; can be assigned =
from a shared_ptr&lt;DERIVED&gt; and they still share the refcount. This wi=
ll require some surgery in the shared_ptr class I suspect. Thinking about t=
he details of this will reveal new insights, no doubt.<br></font></span></b=
lockquote><div><span lang=3D"EN-US"><font face=3D"georgia, serif"><br></fon=
t></span></div><div><span lang=3D"EN-US"><div style=3D"font-family:georgia,=
serif">This is a question I&#39;ve been thinking about over and over again.=
 On the one hand, if the lifetime issue is coupled with the =E2=80=9Cproxie=
s=E2=80=9D, it violates the single responsibility principle, and it becomes=
 unfriendly to =E2=80=9Cstack objects=E2=80=9D, whose lifetime is controlle=
d by the execution of program, but it seems to be easier to use. On the oth=
er hand, if the lifetime issue is decoupled from the =E2=80=9Cproxies=E2=80=
=9D, users are responsible for managing the lifetime, however, they are fre=
e to specify the algorithms (for =E2=80=9Cheap objects=E2=80=9D, from new/d=
elete to GC).</div><div style=3D"font-family:georgia,serif"><br></div><div =
style=3D"font-family:georgia,serif">After some research, I found it unneces=
sary to couple the lifetime issue with the =E2=80=9Cproxies=E2=80=9D at all=
, because most situations that require polymorphism are implementable witho=
ut dynamic memory allocation, as the example mentioned earlier demonstrates=
..</div></span></div></div></blockquote><div><br>Really? Because `std::funct=
ion` disagrees with you. `std::function` is functionally a proxy for a type=
 that is callable with the `operator()` overload specified by the `function=
`&#39;s template parameter. And yet, it also requires copyable value semant=
ics.<br><br>So clearly there is a genuine need for type-erasure+value seman=
tics. Your personal use cases may not need it, but if `function` (and `any`=
 for that matter) are any indication, combining the two is something people=
 really do use.<br></div></div></blockquote><div><br></div><div><span style=
=3D"font-family:georgia,serif">As you think copying the wrapped object is s=
ometimes necessary, could you provide a meaningful use case which is inconv=
enient to implement with the proxy or may reduce runtime overhead while imp=
lemented with std::function?</span></div></blockquote><div><br>OK, let&#39;=
s say you want to use a reference proxy to implement a copyable value proxy=
.. To do that, you have to store the reference proxy, which is going to take=
 up (at least) a pointer of storage. You also need to store sufficient spac=
e for your own pointer to your own type-erased allocated object (possibly w=
ith small storage optimization). You can&#39;t use the proxy&#39;s storage =
because you don&#39;t know the type to extract from the proxy in order to d=
elete it. So you need to store your own type-erasure machinery to do the ac=
tual deleting.<br><br>So a `std::function` implemented in terms of a refere=
nce proxy would be less efficient than `std::function` implemented by itsel=
f. As would any other value-semantics type implemented around a reference.<=
/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/332280b7-e28d-494b-bd09-dc07ecd3baa8%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/332280b7-e28d-494b-bd09-dc07ecd3baa8=
%40isocpp.org</a>.<br />

------=_Part_567_1293647777.1494691900227--

------=_Part_566_1163057103.1494691900227--

.


Author: Mingxin Wang <wmx16835vv@163.com>
Date: Sat, 13 May 2017 19:24:29 -0700 (PDT)
Raw View
------=_Part_773_1543157823.1494728669752
Content-Type: multipart/alternative;
 boundary="----=_Part_774_742746442.1494728669753"

------=_Part_774_742746442.1494728669753
Content-Type: text/plain; charset="UTF-8"

Dear Mr. Bengt Gustafsson and Mr. Nicol Bolas,

Thank you for your ideas.

Such requirements really do exist! But I think this is more appropriate to
be a library feature rather than a lanuage feature to *bind* a value to a
proxy. I have just built a "Wrapper" class, as is shown below:

template <class P /*, class Allocator = std::allocator<void>*/>
    // Maybe some allocator is allowed here
class Wrapper {
 public:
  template <class Data>
  Wrapper(Data data) :
      data_(new Implementation<Data>(std::move(data))),
      p_(static_cast<Implementation<Data>*>(data_.get())->get()) {}

  Wrapper(const Wrapper& rhs) :
      data_(rhs.data_.get() == nullptr ? nullptr : rhs.data_->clone()),
    // The new data is a copy from the original data with polymorphism
      p_(rhs.p_) {}

  Wrapper() = default;
  Wrapper(Wrapper&&) = default;

  /* Access to the proxy */
  P& get() { return p_; }
  operator P& () { return p_; }

 private:
  class Abstraction {
   public:
    /* Pure virtual methods to construct and destruct */
    virtual Abstraction* clone() = 0;
    virtual ~Abstraction() {}
  };

  template <class Data>
  class Implementation : public Abstraction {
   public:
    Implementation(Data&& data) : data_(std::forward<Data>(data)) {}
    Implementation(const Data& data) : data_(data) {}

    Data& get() { return data_; }

    Abstraction* clone() override { return new Implementation(data_); }

   private:
    Data data_;
  };

  /* The two data structures hold distinct pointers */
  std::unique_ptr<Abstraction> data_;
  P p_;
};

*With this class, it is possible to use "Wrapper<SomeProxy>" to turn a
proxy into a value wrapper.* But as it is a wrapper (like
"std::reference_wrapper" does), certain member functions are provided to
access the proxy ("get()" and "operator P&").

I think this is enough so far.

P.S. It is possible for a proxy to proxy any type, including member
functions, as long as they are not temporary variables:
auto f = std::bind(...);
Runnable r(f);

Mingxin Wang

On Saturday, May 13, 2017 at 9:29:14 PM UTC+8, Bengt Gustafsson wrote:
>
> As you think copying the wrapped object is sometimes necessary, could you
>>> provide a meaningful use case which is inconvenient to implement with the
>>> proxy or may reduce runtime overhead while implemented with std::function?
>>>
>>
> This would happen often, for instance in a std::vector<MyProxy> which, as
> the proxy is by value should own its elements regardless of their actual
> types. I think this shows the gist of the ownership problem, because if you
> have a std::vector<MyProxy*> then each vector element should be able to
> point to any object fulfilling MyProxy. But in this case, where is the
> actual proxy object performing the method translation?
>
> I think that the list that Jakob Riedle wrote, and which I copied below
> shows the basic idea to start out from. It must be noted that a reference
> to a proxy as in "Callable<void()>& c2 = f1;" is not a normal reference,
> for what would it refer to? Instead it is a "by reference proxy" which the
> compiler understands how to create, thereby allowing different types of
> ownership semantics. This only goes so far though, it doesn't solve the
> std::vector<MyProxy*> case. Possibly a std::vector<MyProxy&> could be
> allowed but this seems odd as containers of references are not allowed in
> general.
>
> std::function<void()> f1 = /**/;
>> std::function<void()> f2();
>>
>> const std::function<void()> f3 = /**/;
>> Callable<void()> c1 = f1; // This copies f1. Internally, an lvalue
>> object of type std::function<void()> is held.
>> Callable<void()>& c2 = f1; // This references f1. Internally, an lvalue
>> reference (std::function<void()>&) is stored.
>> Callable<void()>&& c3 = f2(); // Internally stored as '
>> std::function<void()>&&'.
>> Callable<void()> c4 = f2(); // This moves the result of f2 into c4.
>> Internally stored as real std::function<void()> lvalue .
>> const Callable<void()>& c4 = f3; //Internally 'const &' as handle.
>> // and so on...
>>
>
>  Another thing resulting from this is that this function has a by value
> parameter of type 'reference proxy to MyProxy':
>
> void myFunc(MyProxy& s);
>
> This by value object contains a pointer to the actual parameter and a
> vtable pointer (or similar) to allow myFunc to call the methods of MyProxy
> regardless of the actual parameter type.
>
> This reuse of the & operator clashes with the possibility to create a
> reference to a proxy, so if myFunc needs to forward s to a sub-function a
> deep copy has to be made (which is just two pointers, but anyway).
>
> Thus it looks as reusing & to indicate proxy ownership is not appropriate
> after all, despite the elegance. We need to be able to specify both a
> reference to a proxy and a proxy which refers to the actual object.
>
> I would like this to work, but then we must disentangle how concept
> contents maps to proxy contents:
>
> concept MyConcept { .... };
>
> class MyClass { ... };      // Class that fulfills MyConcept
>
> MyClass obj;
> MyClass& ref = obj;
>
> std::val_proxy<MyConcept> vp = obj;   // Deep copies obj into some
> internal or heap storage.
> std::ref_proxy<MyConcept> rp = obj;   // Refers to obj.
>
> More importanty:
>
> myRefFun(std::ref_proxy<MyConcept> ra);
>
> myRefFun(obj);    // Refers to obj
> myRefFun(rp);      // deep-copies the ref_proxy<MyConcept> rp as expected
> myRefFun(vp);     // Creates a ref_proxy from the val_proxy by refering to
> the internal copy of obj
>
> std::vector<std::ref_proxy<MyConcept>> myVec;   // This can now be done,
> and you can push back references to any complying objects.
>
> The std::ref_proxy and std::val_proxy templates must be magic on the same
> level as initializer_list which seems to be a library class template but is
> magic. This ducks the issues of having to add keywords or new/reused
> operators. It still does not solve the problem of shared ownership between
> real and proxy pointers as elegantly as between sub- and baseclass shared
> pointers, which brings me back to the original complaint of mine that
> ownership and proxying issues should be separated.
>
> What I think we need is a lower level feature which can be used by
> std::ref_proxy and std::val_proxy as well as any number of other similar
> templates such as shared_proxy and unique_proxy. Something like this:
>
> template<concept C> class ref_proxy {
> public:
>     template<C S> proxy(S& src) : mObject(&src), c(src) {}
>
>      C(mObject);
>
> private:
>      C* mObject;
> C c;
> };
>
> This introduces concepts as template parameters in order to create a
> "higher order template". The first magic happens on the C(mObject) line
> which indicates that the mObject pointer is to be used as 'this' in
> implementations of all methods requires by C. The second magic is the C*
> which is not a normal pointer but a
>

--
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/0e6a347a-c299-4241-b92c-e952c32c254e%40isocpp.org.

------=_Part_774_742746442.1494728669753
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div><font face=3D"georgia, serif">Dear Mr. Bengt Gustafss=
on and Mr. Nicol Bolas,</font><br></div><div><font face=3D"georgia, serif">=
<br></font></div><div><font face=3D"georgia, serif">Thank you for your idea=
s.</font></div><div><font face=3D"georgia, serif"><br></font></div><div><fo=
nt face=3D"georgia, serif">Such requirements really do exist! But I think t=
his is more appropriate to be a library feature rather than a lanuage featu=
re to <b>bind</b> a value to a proxy. I have just built a &quot;Wrapper&quo=
t; class, as is shown below:</font></div><div><br></div><div><div class=3D"=
prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: brea=
k-word; background-color: rgb(250, 250, 250);"><code class=3D"prettyprint">=
<div class=3D"subprettyprint"><font color=3D"#660066"><div class=3D"subpret=
typrint">template &lt;class P /*, class Allocator =3D std::allocator&lt;voi=
d&gt;*/&gt; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // Mayb=
e some allocator is allowed here</div><div class=3D"subprettyprint">class W=
rapper {</div><div class=3D"subprettyprint">=C2=A0public:</div><div class=
=3D"subprettyprint">=C2=A0 template &lt;class Data&gt;</div><div class=3D"s=
ubprettyprint">=C2=A0 Wrapper(Data data) :</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 =C2=A0 data_(new Implementation&lt;Data&gt;(std::move(data=
))),</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 p_(static_cast=
&lt;Implementation&lt;Data&gt;*&gt;(data_.get())-&gt;get()) {}</div><div cl=
ass=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 Wrapp=
er(const Wrapper&amp; rhs) :</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 =C2=A0 data_(rhs.data_.get() =3D=3D nullptr ? nullptr : rhs.data_-&gt;c=
lone()), =C2=A0 =C2=A0 =C2=A0 =C2=A0 // The new data is a copy from the ori=
ginal data with polymorphism</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 =C2=A0 p_(rhs.p_) {}</div><div class=3D"subprettyprint"><br></div><div =
class=3D"subprettyprint">=C2=A0 Wrapper() =3D default;</div><div class=3D"s=
ubprettyprint">=C2=A0 Wrapper(Wrapper&amp;&amp;) =3D default;</div><div cla=
ss=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Acc=
ess to the proxy */</div><div class=3D"subprettyprint">=C2=A0 P&amp; get() =
{ return p_; }</div><div class=3D"subprettyprint">=C2=A0 operator P&amp; ()=
 { return p_; }</div><div class=3D"subprettyprint"><br></div><div class=3D"=
subprettyprint">=C2=A0private:</div><div class=3D"subprettyprint">=C2=A0 cl=
ass Abstraction {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0public:</=
div><div class=3D"subprettyprint">=C2=A0 =C2=A0 /* Pure virtual methods to =
construct and destruct */</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
virtual Abstraction* clone() =3D 0;</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 virtual ~Abstraction() {}</div><div class=3D"subprettyprint">=C2=
=A0 };</div><div class=3D"subprettyprint"><br></div><div class=3D"subpretty=
print">=C2=A0 template &lt;class Data&gt;</div><div class=3D"subprettyprint=
">=C2=A0 class Implementation : public Abstraction {</div><div class=3D"sub=
prettyprint">=C2=A0 =C2=A0public:</div><div class=3D"subprettyprint">=C2=A0=
 =C2=A0 Implementation(Data&amp;&amp; data) : data_(std::forward&lt;Data&gt=
;(data)) {}</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 Implementation=
(const Data&amp; data) : data_(data) {}</div><div class=3D"subprettyprint">=
<br></div><div class=3D"subprettyprint">=C2=A0 =C2=A0 Data&amp; get() { ret=
urn data_; }</div><div class=3D"subprettyprint"><br></div><div class=3D"sub=
prettyprint">=C2=A0 =C2=A0 Abstraction* clone() override { return new Imple=
mentation(data_); }</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0private:</div><div class=3D"subprettyprint=
">=C2=A0 =C2=A0 Data data_;</div><div class=3D"subprettyprint">=C2=A0 };</d=
iv><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=
=C2=A0 /* The two data structures hold distinct pointers */</div><div class=
=3D"subprettyprint">=C2=A0 std::unique_ptr&lt;Abstraction&gt; data_;</div><=
div class=3D"subprettyprint">=C2=A0 P p_;</div><div class=3D"subprettyprint=
">};</div></font></div></code></div><br><font face=3D"georgia, serif"><b>Wi=
th this class, it is possible to use &quot;Wrapper&lt;SomeProxy&gt;&quot; t=
o turn a proxy into a value wrapper.</b> But as it is a wrapper (like &quot=
;std::reference_wrapper&quot; does), certain member functions are provided =
to access the proxy (&quot;get()&quot; and &quot;operator P&amp;&quot;).</f=
ont></div><div><font face=3D"georgia, serif"><br></font></div><div><font fa=
ce=3D"georgia, serif">I think this is enough so far.</font></div><div><font=
 face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, serif=
">P.S. It is possible for a proxy to proxy any type, including member funct=
ions, as long as=C2=A0they are not temporary variables:</font></div><div><f=
ont face=3D"georgia, serif"><div class=3D"prettyprint" style=3D"border: 1px=
 solid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(250=
, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><di=
v class=3D"subprettyprint">auto f =3D std::bind(...);</div><div class=3D"su=
bprettyprint">Runnable r(f);</div></div></code></div></font></div><div><fon=
t face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, seri=
f">Mingxin Wang</font></div><div><br></div>On Saturday, May 13, 2017 at 9:2=
9:14 PM UTC+8, Bengt Gustafsson wrote:<blockquote class=3D"gmail_quote" sty=
le=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"><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><div style=3D"backgroun=
d-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;b=
order-width:1px"><code><div><span style=3D"font-family:georgia,serif;backgr=
ound-color:rgb(255,255,255)">As you think copying the wrapped object is som=
etimes necessary, could you provide a meaningful use case which is inconven=
ient to implement with the proxy or may reduce runtime overhead while imple=
mented with std::function?</span></div></code></div></div></div></blockquot=
e></blockquote><div><br></div><div>This would happen often, for instance in=
 a std::vector&lt;MyProxy&gt; which, as the proxy is by value should own it=
s elements regardless of their actual types. I think this shows the gist of=
 the ownership problem, because if you have a std::vector&lt;MyProxy*&gt; t=
hen each vector element should be able to point to any object fulfilling My=
Proxy. But in this case, where is the actual proxy object performing the me=
thod translation?</div><div><br></div><div>I think that the list that Jakob=
 Riedle wrote, and which I copied below shows the basic idea to start out f=
rom. It must be noted that a reference to a proxy as in &quot;<span style=
=3D"font-family:monospace;background-color:rgb(250,250,250);color:rgb(102,0=
,102)">Callable</span><span style=3D"font-family:monospace;background-color=
:rgb(250,250,250);color:rgb(102,102,0)">&lt;</span><span style=3D"font-fami=
ly:monospace;background-color:rgb(250,250,250);color:rgb(0,0,136)">void</sp=
an><span style=3D"font-family:monospace;background-color:rgb(250,250,250);c=
olor:rgb(102,102,0)">()&gt;&amp;</span><span style=3D"font-family:monospace=
;background-color:rgb(250,250,250);color:rgb(0,0,0)">=C2=A0c2=C2=A0</span><=
span style=3D"font-family:monospace;background-color:rgb(250,250,250);color=
:rgb(102,102,0)">=3D</span><span style=3D"font-family:monospace;background-=
color:rgb(250,250,250);color:rgb(0,0,0)">=C2=A0f1</span><span style=3D"font=
-family:monospace;background-color:rgb(250,250,250);color:rgb(102,102,0)">;=
&quot;</span>=C2=A0<wbr>is not a normal reference, for what would it refer =
to? Instead it is a &quot;by reference proxy&quot; which the compiler under=
stands how to create, thereby allowing different types of ownership semanti=
cs. This only goes so far though, it doesn&#39;t solve the std::vector&lt;M=
yProxy*&gt; case. Possibly a std::vector&lt;MyProxy&amp;&gt; could be allow=
ed but this seems odd as containers of references are not allowed in genera=
l.</div><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0p=
x 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><d=
iv style=3D"border-width:1px;border-style:solid;border-color:rgb(187,187,18=
7);background-color:rgb(250,250,250);word-wrap:break-word"><code><div><span=
 style=3D"color:rgb(0,0,0)">std</span><span style=3D"color:rgb(102,102,0)">=
::</span><span style=3D"color:rgb(0,0,136)">function</span><span style=3D"c=
olor:rgb(102,102,0)">&lt;</span><span style=3D"color:rgb(0,0,136)">void</sp=
an><span style=3D"color:rgb(102,102,0)">()&gt;</span><span style=3D"color:r=
gb(0,0,0)">=C2=A0f1=C2=A0</span><span style=3D"color:rgb(102,102,0)">=3D</s=
pan><span style=3D"color:rgb(0,0,0)">=C2=A0</span><span style=3D"color:rgb(=
136,0,0)">/**<wbr>/</span><span style=3D"color:rgb(102,102,0)">;</span><spa=
n style=3D"color:rgb(0,0,0)"><br>std</span><span style=3D"color:rgb(102,102=
,0)">::</span><span style=3D"color:rgb(0,0,136)">function</span><span style=
=3D"color:rgb(102,102,0)">&lt;</span><span style=3D"color:rgb(0,0,136)">voi=
d</span><span style=3D"color:rgb(102,102,0)">()&gt;</span><span style=3D"co=
lor:rgb(0,0,0)">=C2=A0f2</span><span style=3D"color:rgb(102,102,0)">();</sp=
an><span style=3D"color:rgb(0,0,0)"><br><br></span><span style=3D"color:rgb=
(0,0,136)">const</span><span style=3D"color:rgb(0,0,0)">=C2=A0std</span><sp=
an style=3D"color:rgb(102,102,0)">::</span><span style=3D"color:rgb(0,0,136=
)">function</span><span style=3D"color:rgb(102,102,0)">&lt;</span><span sty=
le=3D"color:rgb(0,0,136)">void</span><span style=3D"color:rgb(102,102,0)">(=
)&gt;</span><span style=3D"color:rgb(0,0,0)">=C2=A0<wbr>f3=C2=A0</span><spa=
n style=3D"color:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)"=
>=C2=A0</span><span style=3D"color:rgb(136,0,0)">/**/</span><span style=3D"=
color:rgb(102,102,0)">;</span><span style=3D"color:rgb(0,0,0)"><br></span><=
span style=3D"color:rgb(102,0,102)">Callable</span><span style=3D"color:rgb=
(102,102,0)">&lt;</span><span style=3D"color:rgb(0,0,136)">void</span><span=
 style=3D"color:rgb(102,102,0)">()&gt;</span><span style=3D"color:rgb(0,0,0=
)">=C2=A0c1=C2=A0</span><span style=3D"color:rgb(102,102,0)">=3D</span><spa=
n style=3D"color:rgb(0,0,0)">=C2=A0f1</span><span style=3D"color:rgb(102,10=
2,0)">;</span><span style=3D"color:rgb(0,0,0)">=C2=A0</span><span style=3D"=
color:rgb(136,0,0)">// This copies f1. Internally, an lvalue object of type=
 std::function&lt;void()&gt; is held.</span><span style=3D"color:rgb(0,0,0)=
"><br></span><span style=3D"color:rgb(102,0,102)">Callable</span><span styl=
e=3D"color:rgb(102,102,0)">&lt;</span><span style=3D"color:rgb(0,0,136)">vo=
id</span><span style=3D"color:rgb(102,102,0)">()&gt;&amp;</span><span style=
=3D"color:rgb(0,0,0)">=C2=A0c2=C2=A0</span><span style=3D"color:rgb(102,102=
,0)">=3D</span><span style=3D"color:rgb(0,0,0)">=C2=A0f1</span><span style=
=3D"color:rgb(102,102,0)">;</span><span style=3D"color:rgb(0,0,0)">=C2=A0</=
span><span style=3D"color:rgb(136,0,0)">// This references f1. Internally, =
an lvalue reference (std::function&lt;void()&gt;&amp;) is stored.</span><sp=
an style=3D"color:rgb(0,0,0)"><br></span><span style=3D"color:rgb(102,0,102=
)">Callable</span><span style=3D"color:rgb(102,102,0)">&lt;</span><span sty=
le=3D"color:rgb(0,0,136)">void</span><span style=3D"color:rgb(102,102,0)">(=
)&gt;&amp;&amp;</span><span style=3D"color:rgb(0,0,0)">=C2=A0c3=C2=A0</span=
><span style=3D"color:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,=
0,0)">=C2=A0f2</span><span style=3D"color:rgb(102,102,0)">();</span><span s=
tyle=3D"color:rgb(0,0,0)">=C2=A0</span><span style=3D"color:rgb(136,0,0)"><=
wbr>// Internally stored as &#39;</span><span style=3D"color:rgb(136,0,0);f=
ont-family:Arial,Helvetica,sans-serif">std::function&lt;void()&gt;</span><s=
pan style=3D"color:rgb(136,0,0);font-family:Arial,Helvetica,sans-serif">&am=
p;&amp;&#39;.</span></div><div><span style=3D"color:rgb(102,0,102)">Callabl=
e</span><span style=3D"color:rgb(102,102,0)">&lt;</span><span style=3D"colo=
r:rgb(0,0,136)">void</span><span style=3D"color:rgb(102,102,0)">()&gt;</spa=
n><span style=3D"color:rgb(0,0,0)">=C2=A0c4=C2=A0</span><span style=3D"colo=
r:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)">=C2=A0f2</span=
><span style=3D"color:rgb(102,102,0)">();</span><span style=3D"color:rgb(0,=
0,0)">=C2=A0</span><span style=3D"color:rgb(136,0,0)">// This moves the res=
ult of f2 into c4. Internally stored as real=C2=A0</span><span style=3D"col=
or:rgb(136,0,0);font-family:Arial,Helvetica,sans-serif">std::function&lt;vo=
id()&gt;=C2=A0</span><span style=3D"font-family:Arial,Helvetica,sans-serif;=
color:rgb(136,0,0)">lva<wbr>lue=C2=A0</span><span style=3D"font-family:Aria=
l,Helvetica,sans-serif;color:rgb(136,0,0)">.</span></div><div><span style=
=3D"color:rgb(0,0,136)">const</span><span style=3D"color:rgb(0,0,0)">=C2=A0=
</span><span style=3D"color:rgb(102,0,102)">Callable</span><span style=3D"c=
olor:rgb(102,102,0)">&lt;</span><span style=3D"color:rgb(0,0,136)">void</sp=
an><span style=3D"color:rgb(102,102,0)">()&gt;&amp;</span><span style=3D"co=
lor:rgb(0,0,0)">=C2=A0c4=C2=A0</span><span style=3D"color:rgb(102,102,0)">=
=3D</span><span style=3D"color:rgb(0,0,0)">=C2=A0<wbr>f3</span><span style=
=3D"color:rgb(102,102,0)">;</span><span style=3D"color:rgb(0,0,0)">=C2=A0</=
span><span style=3D"color:rgb(136,0,0)">//Internally &#39;const &amp;&#39; =
as handle.</span><span style=3D"color:rgb(0,0,0)"><br></span><span style=3D=
"color:rgb(136,0,0)">// and so on...</span></div></code></div></blockquote>=
<div><br></div><div>=C2=A0Another thing resulting from this is that this fu=
nction has a by value parameter of type &#39;reference proxy to MyProxy&#39=
;:</div><div><br></div><div>void myFunc(MyProxy&amp; s);</div><div><br></di=
v><div>This by value object contains a pointer to the actual parameter and =
a vtable pointer (or similar) to allow myFunc to call the methods of MyProx=
y regardless of the actual parameter type.</div><div><br></div><div>This re=
use of the &amp; operator clashes with the possibility to create a referenc=
e to a proxy, so if myFunc needs to forward s to a sub-function a deep copy=
 has to be made (which is just two pointers, but anyway).</div><div><br></d=
iv><div>Thus it looks as reusing &amp; to indicate proxy ownership is not a=
ppropriate after all, despite the elegance. We need to be able to specify b=
oth a reference to a proxy and a proxy which refers to the actual object.</=
div><div><br></div><div>I would like this to work, but then we must disenta=
ngle how concept contents maps to proxy contents:</div><div><br></div><div>=
concept MyConcept { .... };</div><div><br></div><div>class MyClass { ... };=
 =C2=A0 =C2=A0 =C2=A0// Class that fulfills MyConcept</div><div><br></div><=
div>MyClass obj;</div><div>MyClass&amp; ref =3D obj;</div><div><br></div><d=
iv>std::val_proxy&lt;MyConcept&gt; vp =3D obj; =C2=A0 // Deep copies obj in=
to some internal or heap storage.</div><div>std::ref_proxy&lt;MyConcept&gt;=
 rp =3D obj; =C2=A0 // Refers to obj.</div><div><br></div><div>More importa=
nty:</div><div><br></div><div>myRefFun(std::ref_proxy&lt;<wbr>MyConcept&gt;=
 ra);</div><div><br></div><div>myRefFun(obj); =C2=A0 =C2=A0// Refers to obj=
</div><div>myRefFun(rp); =C2=A0 =C2=A0 =C2=A0// deep-copies the ref_proxy&l=
t;MyConcept&gt; rp as expected</div><div>myRefFun(vp); =C2=A0 =C2=A0 // Cre=
ates a ref_proxy from the val_proxy by refering to the internal copy of obj=
</div><div><br></div><div>std::vector&lt;std::ref_proxy&lt;<wbr>MyConcept&g=
t;&gt; myVec; =C2=A0 // This can now be done, and you can push back referen=
ces to any complying objects.</div><div><br></div><div>The std::ref_proxy a=
nd std::val_proxy templates must be magic on the same level as initializer_=
list which seems to be a library class template but is magic. This ducks th=
e issues of having to add keywords or new/reused operators. It still does n=
ot solve the problem of shared ownership between real and proxy pointers as=
 elegantly as between sub- and baseclass shared pointers, which brings me b=
ack to the original complaint of mine that ownership and proxying issues sh=
ould be separated.</div><div><br></div><div>What I think we need is a lower=
 level feature which can be used by std::ref_proxy and std::val_proxy as we=
ll as any number of other similar templates such as shared_proxy and unique=
_proxy. Something like this:</div><div><br></div><div>template&lt;concept C=
&gt; class ref_proxy {</div><div>public:</div><div>=C2=A0 =C2=A0 template&l=
t;C S&gt; proxy(S&amp; src) : mObject(&amp;src), c(src) {}</div><div><br></=
div><div>=C2=A0 =C2=A0 =C2=A0C(mObject);</div><div><br></div><div>private:<=
/div><div>=C2=A0 =C2=A0 =C2=A0C* mObject;=C2=A0</div><div>C c;</div><div>};=
</div><div><br></div><div>This introduces concepts as template parameters i=
n order to create a &quot;higher order template&quot;. The first magic happ=
ens on the C(mObject) line which indicates that the mObject pointer is to b=
e used as &#39;this&#39; in implementations of all methods requires by C. T=
he second magic is the C* which is not a normal pointer but a=C2=A0</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&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/0e6a347a-c299-4241-b92c-e952c32c254e%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/0e6a347a-c299-4241-b92c-e952c32c254e=
%40isocpp.org</a>.<br />

------=_Part_774_742746442.1494728669753--

------=_Part_773_1543157823.1494728669752--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 13 May 2017 19:56:16 -0700 (PDT)
Raw View
------=_Part_742_1196276892.1494730576686
Content-Type: multipart/alternative;
 boundary="----=_Part_743_1708105424.1494730576686"

------=_Part_743_1708105424.1494730576686
Content-Type: text/plain; charset="UTF-8"

On Saturday, May 13, 2017 at 10:24:29 PM UTC-4, Mingxin Wang wrote:
>
> Dear Mr. Bengt Gustafsson and Mr. Nicol Bolas,
>
> Thank you for your ideas.
>
> Such requirements really do exist! But I think this is more appropriate to
> be a library feature rather than a lanuage feature to *bind* a value to a
> proxy. I have just built a "Wrapper" class, as is shown below:
>
>
[...]
>

>
*With this class, it is possible to use "Wrapper<SomeProxy>" to turn a
> proxy into a value wrapper.* But as it is a wrapper (like
> "std::reference_wrapper" does), certain member functions are provided to
> access the proxy ("get()" and "operator P&").
>
> I think this is enough so far.
>

The deficiencies relative to a hand-written type-erased type are readily
apparent:

1) The wrapper takes up more memory.
2) The wrapper is less efficient (since it has two type-erasures instead of
just one).
3) The wrapper is *far* less convenient to actually *use*, since it's not
the actual proxy; you have to use `get` or an implicit conversion to get at
the behavior you want.

If it would be better for a user to hand-write a type-erased type rather
than use your language-based one, then your language feature has design
problems.

Is not the whole point of this feature to make type-erasure a first-class
part of the language? If so, then it needs to be usable by *everyone* who
wants to use type-erasure, not just everyone who wants reference semantics.
Concepts doesn't have this flaw; if you want to pass a value that satisfies
a concept around by value, you can (so long as the concept allows such
copying/moving).

Why can't proxies?

P.S. It is possible for a proxy to proxy any type, including member
> functions, as long as they are not temporary variables:
> auto f = std::bind(...);
> Runnable r(f);
>
>
But now you have to make sure that `f` stays alive so long as `r` does.
With regular function pointers, you don't have to care; function pointers
are valid forever. As are member pointers, but those don't work here.

If you were to write a hand-written `Runnable<Func>` type, even if it only
has reference semantics, you would still give it native support for member
pointers. Because those are genuine "runnables" and should have first-class
access like function pointers.

So again, I find myself saying that if hand-written type-erased types are
better than your language-based ones, then your language feature has design
problems.

--
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/f529e3c1-dc44-4a1b-86db-a6a3f5befc89%40isocpp.org.

------=_Part_743_1708105424.1494730576686
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Saturday, May 13, 2017 at 10:24:29 PM UTC-4, Mingxin Wa=
ng 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"><div=
><font face=3D"georgia, serif">Dear Mr. Bengt Gustafsson and Mr. Nicol Bola=
s,</font><br></div><div><font face=3D"georgia, serif"><br></font></div><div=
><font face=3D"georgia, serif">Thank you for your ideas.</font></div><div><=
font face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, s=
erif">Such requirements really do exist! But I think this is more appropria=
te to be a library feature rather than a lanuage feature to <b>bind</b> a v=
alue to a proxy. I have just built a &quot;Wrapper&quot; class, as is shown=
 below:</font></div><div>=C2=A0</div></div></blockquote><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div dir=3D"ltr"><div></div><div>[...]<br></div=
></div></blockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0px =
0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex=
;"><div>=C2=A0</div></blockquote><blockquote class=3D"gmail_quote" style=3D=
"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex=
;"><div dir=3D"ltr"><div><font face=3D"georgia, serif"><b>With this class, =
it is possible to use &quot;Wrapper&lt;SomeProxy&gt;&quot; to turn a proxy =
into a value wrapper.</b> But as it is a wrapper (like &quot;std::reference=
_wrapper&quot; does), certain member functions are provided to access the p=
roxy (&quot;get()&quot; and &quot;operator P&amp;&quot;).</font></div><div>=
<font face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, =
serif">I think this is enough so far.</font></div></div></blockquote><div><=
br>The deficiencies relative to a hand-written type-erased type are readily=
 apparent:<br><br>1) The wrapper takes up more memory.<br>2) The wrapper is=
 less efficient (since it has two type-erasures instead of just one).<br>3)=
 The wrapper is <i>far</i> less convenient to actually <i>use</i>, since it=
&#39;s not the actual proxy; you have to use `get` or an implicit conversio=
n to get at the behavior you want.<br><br>If it would be better for a user =
to hand-write a type-erased type rather than use your language-based one, t=
hen your language feature has design problems.<br><br>Is not the whole poin=
t of this feature to make type-erasure a first-class part of the language? =
If so, then it needs to be usable by <i>everyone</i> who wants to use type-=
erasure, not just everyone who wants reference semantics. Concepts doesn&#3=
9;t have this flaw; if you want to pass a value that satisfies a concept ar=
ound by value, you can (so long as the concept allows such copying/moving).=
<br><br>Why can&#39;t proxies?<br><br></div><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><div dir=3D"ltr"><div><font face=3D"georgia, serif">P.S. It i=
s possible for a proxy to proxy any type, including member functions, as lo=
ng as=C2=A0they are not temporary variables:</font></div><div><font face=3D=
"georgia, serif"><div style=3D"border:1px solid rgb(187,187,187);word-wrap:=
break-word;background-color:rgb(250,250,250)"><code><div><div>auto f =3D st=
d::bind(...);</div><div>Runnable r(f);</div></div></code></div></font></div=
><div><font face=3D"georgia, serif"><br></font></div></div></blockquote><di=
v><br>But now you have to make sure that `f` stays alive so long as `r` doe=
s. With regular function pointers, you don&#39;t have to care; function poi=
nters are valid forever. As are member pointers, but those don&#39;t work h=
ere.<br><br>If you were to write a hand-written `Runnable&lt;Func&gt;` type=
, even if it only has reference semantics, you would still give it native s=
upport for member pointers. Because those are genuine &quot;runnables&quot;=
 and should have first-class access like function pointers.<br><br>So again=
, I find myself saying that if hand-written type-erased types are better th=
an your language-based ones, then your language feature has design problems=
..<br></div></div>

<p></p>

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

------=_Part_743_1708105424.1494730576686--

------=_Part_742_1196276892.1494730576686--

.


Author: Mingxin Wang <wmx16835vv@163.com>
Date: Sat, 13 May 2017 23:11:41 -0700 (PDT)
Raw View
------=_Part_780_1639054629.1494742301841
Content-Type: multipart/alternative;
 boundary="----=_Part_781_402921243.1494742301841"

------=_Part_781_402921243.1494742301841
Content-Type: text/plain; charset="UTF-8"

On Sunday, May 14, 2017 at 10:56:16 AM UTC+8, Nicol Bolas wrote:
>
> On Saturday, May 13, 2017 at 10:24:29 PM UTC-4, Mingxin Wang wrote:
>>
>> Dear Mr. Bengt Gustafsson and Mr. Nicol Bolas,
>>
>> Thank you for your ideas.
>>
>> Such requirements really do exist! But I think this is more appropriate
>> to be a library feature rather than a lanuage feature to *bind* a value
>> to a proxy. I have just built a "Wrapper" class, as is shown below:
>>
>>
> [...]
>>
>
>>
> *With this class, it is possible to use "Wrapper<SomeProxy>" to turn a
>> proxy into a value wrapper.* But as it is a wrapper (like
>> "std::reference_wrapper" does), certain member functions are provided to
>> access the proxy ("get()" and "operator P&").
>>
>> I think this is enough so far.
>>
>
> The deficiencies relative to a hand-written type-erased type are readily
> apparent:
>
> 1) The wrapper takes up more memory.
>

On my compiler (G++ 6.3.0 x64):

sizeof(std::function<void()>) == 32;
sizeof(Wrapper<Runnable>) == 24;

2) The wrapper is less efficient (since it has two type-erasures instead of
> just one).
>

To test the performance of the wrapper, I did a little experiment on my PC
(with G++ 6.3.0 x64, Command line: g++ -march=corei7-avx -O2 -Wall
-std=c++17):

Experiment A:
void small_demo(); // An ordinary function

constexpr int UPPER = 10000000;

for (int i = 0; i < UPPER; ++i) {
  std::function<void()> f(small_demo);
}

Experiment B:
void small_demo(); // An ordinary function

constexpr int UPPER = 10000000;

for (int i = 0; i < UPPER; ++i) {
  Wrapper<Runnable> f(small_demo);
}

Experiment C:
class LargeDemo { // A large enough functor that is not able to be stored
in a std::function<void>
 public:
  void operator()() {}

 private:
  int a[1000];
};

constexpr int UPPER = 10000000;

for (int i = 0; i < UPPER; ++i) {
  std::function<void()> f(large_demo);
}

Experiment D:
class LargeDemo { // A large enough functor that is not able to be stored
in a std::function<void>
 public:
  void operator()() {}

 private:
  int a[1000];
};

constexpr int UPPER = 10000000;

for (int i = 0; i < UPPER; ++i) {
  Wrapper<Runnable> f(large_demo);
}

The result is shown in the table below:

<https://lh3.googleusercontent.com/-b7s_rR8iY9o/WRfuXWeINII/AAAAAAAAAEs/VnaF4_GJmO4Xgt6X185BDyDHtV0XOjq9QCLcB/s1600/%25E5%259B%25BE%25E7%2589%25871.png>

It is not surprising that std::function<void> is much efficient than
Wrapper<Runnable> with small data sets (after compiler optimizations we
have), because it has been specially constructed. But as you can see from
the table, Wrapper<Runnable> is a little more efficient than
std::function<void> with large data sets. Besides, Wrapper<T> is just
a descriptive implementation, compiler vendors may apply other algorithms
to reach a compromise if necessary.

3) The wrapper is *far* less convenient to actually *use*, since it's not
> the actual proxy; you have to use `get` or an implicit conversion to get at
> the behavior you want.
>
> If it would be better for a user to hand-write a type-erased type rather
> than use your language-based one, then your language feature has design
> problems.
>
> Is not the whole point of this feature to make type-erasure a first-class
> part of the language? If so, then it needs to be usable by *everyone* who
> wants to use type-erasure, not just everyone who wants reference semantics.
> Concepts doesn't have this flaw; if you want to pass a value that satisfies
> a concept around by value, you can (so long as the concept allows such
> copying/moving).
>
> Why can't proxies?
>
> P.S. It is possible for a proxy to proxy any type, including member
>> functions, as long as they are not temporary variables:
>> auto f = std::bind(...);
>> Runnable r(f);
>>
>>
> But now you have to make sure that `f` stays alive so long as `r` does.
> With regular function pointers, you don't have to care; function pointers
> are valid forever. As are member pointers, but those don't work here.
>
> If you were to write a hand-written `Runnable<Func>` type, even if it only
> has reference semantics, you would still give it native support for member
> pointers. Because those are genuine "runnables" and should have first-class
> access like function pointers.
>
> That is why I think the "proxies" should be a language feature and the
"wrappers" should be a library feature. Wrappers are not proxies, they are
bound from a proxy and a user-defined implementations, so they should not
have semantics like the "proxies". This is similar with the reason why
std::reference_wrapper do not have the semantics as the wrapped object has.


> So again, I find myself saying that if hand-written type-erased types are
> better than your language-based ones, then your language feature has design
> problems.
>

--
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/4376b734-9a95-46d5-af3e-0aba3e722501%40isocpp.org.

------=_Part_781_402921243.1494742301841
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Sunday, May 14, 2017 at 10:56:16 AM UTC+8, Nicol Bolas =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On Satu=
rday, May 13, 2017 at 10:24:29 PM UTC-4, Mingxin Wang wrote:<blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc=
 solid;padding-left:1ex"><div dir=3D"ltr"><div><font face=3D"georgia, serif=
">Dear Mr. Bengt Gustafsson and Mr. Nicol Bolas,</font><br></div><div><font=
 face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, serif=
">Thank you for your ideas.</font></div><div><font face=3D"georgia, serif">=
<br></font></div><div><font face=3D"georgia, serif">Such requirements reall=
y do exist! But I think this is more appropriate to be a library feature ra=
ther than a lanuage feature to <b>bind</b> a value to a proxy. I have just =
built a &quot;Wrapper&quot; class, as is shown below:</font></div><div>=C2=
=A0</div></div></blockquote><blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div di=
r=3D"ltr"><div></div><div>[...]<br></div></div></blockquote><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex"><div>=C2=A0</div></blockquote><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><font face=3D"georgia, =
serif"><b>With this class, it is possible to use &quot;Wrapper&lt;SomeProxy=
&gt;&quot; to turn a proxy into a value wrapper.</b> But as it is a wrapper=
 (like &quot;std::reference_wrapper&quot; does), certain member functions a=
re provided to access the proxy (&quot;get()&quot; and &quot;operator P&amp=
;&quot;).</font></div><div><font face=3D"georgia, serif"><br></font></div><=
div><font face=3D"georgia, serif">I think this is enough so far.</font></di=
v></div></blockquote><div><br>The deficiencies relative to a hand-written t=
ype-erased type are readily apparent:<br><br>1) The wrapper takes up more m=
emory.</div></div></blockquote><div><br></div><div><font face=3D"georgia, s=
erif">On my compiler (G++ 6.3.0 x64):</font></div><div><br></div><div><div =
class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-w=
rap: break-word; background-color: rgb(250, 250, 250);"><code class=3D"pret=
typrint"><div class=3D"subprettyprint"><font face=3D"courier new, monospace=
"><div style=3D"background-color: rgb(255, 255, 255);"><span style=3D"color=
: #008;" class=3D"styled-by-prettify">sizeof</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">std</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">::</span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">function</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">&lt;</span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">void</span><span style=3D"color: #660;" class=3D"styled-by-prettify">()&g=
t;)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D=3D</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">32</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">;</span></div><div style=3D"backgrou=
nd-color: rgb(255, 255, 255);"><span style=3D"color: #008;" class=3D"styled=
-by-prettify">sizeof</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #606;" class=3D"styled-by-prettify"=
>Wrapper</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&l=
t;</span><span style=3D"color: #606;" class=3D"styled-by-prettify">Runnable=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;)</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">=3D=3D</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #066;" class=3D"styled-by-prettify">24</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">;</span></div></font></div></code></div></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 dir=3D"lt=
r"><div>2) The wrapper is less efficient (since it has two type-erasures in=
stead of just one).<br></div></div></blockquote><div><br></div><div><font f=
ace=3D"georgia, serif">To test the performance of the wrapper, I did a litt=
le experiment on my PC (with G++ 6.3.0 x64, Command line: g++ -march=3Dcore=
i7-avx -O2 -Wall -std=3Dc++17):</font></div><div><font face=3D"georgia, ser=
if"><br></font></div><div><font face=3D"georgia, serif">Experiment A:</font=
></div><div><div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, =
187, 187); word-wrap: break-word; background-color: rgb(250, 250, 250);"><c=
ode class=3D"prettyprint"><div class=3D"subprettyprint"><font color=3D"#660=
066"><div class=3D"subprettyprint">void small_demo(); // An ordinary functi=
on</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprin=
t">constexpr int UPPER =3D 10000000;</div><div class=3D"subprettyprint"><br=
></div><div class=3D"subprettyprint">for (int i =3D 0; i &lt; UPPER; ++i) {=
</div><div class=3D"subprettyprint">=C2=A0 std::function&lt;void()&gt; f(sm=
all_demo);</div><div class=3D"subprettyprint">}</div></font></div></code></=
div><div><font face=3D"georgia, serif"><br></font></div><font face=3D"georg=
ia, serif">Experiment B:</font></div><div><div class=3D"prettyprint" style=
=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background=
-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subp=
rettyprint"><font color=3D"#660066"><div class=3D"subprettyprint">void smal=
l_demo(); // An ordinary function</div><div class=3D"subprettyprint"><br></=
div><div class=3D"subprettyprint">constexpr int UPPER =3D 10000000;</div><d=
iv class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">for (in=
t i =3D 0; i &lt; UPPER; ++i) {</div><div class=3D"subprettyprint">=C2=A0 W=
rapper&lt;Runnable&gt; f(small_demo);</div><div class=3D"subprettyprint">}<=
/div></font></div></code></div><div><font face=3D"georgia, serif"><br></fon=
t></div><font face=3D"georgia, serif">Experiment C:</font></div><div><div c=
lass=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-wr=
ap: break-word; background-color: rgb(250, 250, 250);"><code class=3D"prett=
yprint"><div class=3D"subprettyprint"><font color=3D"#660066"><div class=3D=
"subprettyprint">class LargeDemo { // A large enough functor that is not ab=
le to be stored in a std::function&lt;void&gt;</div><div class=3D"subpretty=
print">=C2=A0public:</div><div class=3D"subprettyprint">=C2=A0 void operato=
r()() {}</div><div class=3D"subprettyprint"><br></div><div class=3D"subpret=
typrint">=C2=A0private:</div><div class=3D"subprettyprint">=C2=A0 int a[100=
0];</div><div class=3D"subprettyprint">};</div><div class=3D"subprettyprint=
"><br></div><div class=3D"subprettyprint">constexpr int UPPER =3D 10000000;=
</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint"=
>for (int i =3D 0; i &lt; UPPER; ++i) {</div><div class=3D"subprettyprint">=
=C2=A0 std::function&lt;void()&gt; f(large_demo);</div><div class=3D"subpre=
ttyprint">}</div></font></div></code></div><font face=3D"georgia, serif"><b=
r>Experiment D:</font></div><div><div class=3D"prettyprint" style=3D"border=
: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-color: rg=
b(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint=
"><font color=3D"#660066"><div class=3D"subprettyprint">class LargeDemo { /=
/ A large enough functor that is not able to be stored in a std::function&l=
t;void&gt;</div><div class=3D"subprettyprint">=C2=A0public:</div><div class=
=3D"subprettyprint">=C2=A0 void operator()() {}</div><div class=3D"subprett=
yprint"><br></div><div class=3D"subprettyprint">=C2=A0private:</div><div cl=
ass=3D"subprettyprint">=C2=A0 int a[1000];</div><div class=3D"subprettyprin=
t">};</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyp=
rint">constexpr int UPPER =3D 10000000;</div><div class=3D"subprettyprint">=
<br></div><div class=3D"subprettyprint">for (int i =3D 0; i &lt; UPPER; ++i=
) {</div><div class=3D"subprettyprint">=C2=A0 Wrapper&lt;Runnable&gt; f(lar=
ge_demo);</div><div class=3D"subprettyprint">}</div></font></div></code></d=
iv><br><font face=3D"georgia, serif">The result is shown in the table below=
:</font></div><div><p class=3D"separator" style=3D"text-align: center; clea=
r: both;"><a imageanchor=3D"1" href=3D"https://lh3.googleusercontent.com/-b=
7s_rR8iY9o/WRfuXWeINII/AAAAAAAAAEs/VnaF4_GJmO4Xgt6X185BDyDHtV0XOjq9QCLcB/s1=
600/%25E5%259B%25BE%25E7%2589%25871.png" style=3D"margin-left: 1em; margin-=
right: 1em;"><img src=3D"https://lh3.googleusercontent.com/-b7s_rR8iY9o/WRf=
uXWeINII/AAAAAAAAAEs/VnaF4_GJmO4Xgt6X185BDyDHtV0XOjq9QCLcB/s400/%25E5%259B%=
25BE%25E7%2589%25871.png" border=3D"0" width=3D"400" height=3D"50"></a></p>=
<div style=3D"text-align: left;"><br></div><div style=3D"text-align: left;"=
><font face=3D"georgia, serif">It is not=C2=A0surprising that std::function=
&lt;void&gt; is much efficient than Wrapper&lt;Runnable&gt; with small data=
 sets (after compiler optimizations we have), because it has been specially=
 constructed. But as you can see from the table, Wrapper&lt;Runnable&gt; is=
 a little more efficient than std::function&lt;void&gt; with large data set=
s. Besides, Wrapper&lt;T&gt; is just a=C2=A0descriptive implementation, com=
piler vendors may apply other algorithms to reach a compromise if necessary=
..</font></div></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 dir=3D"ltr"><div>3) The wrapper is <i>far</i> less convenient to=
 actually <i>use</i>, since it&#39;s not the actual proxy; you have to use =
`get` or an implicit conversion to get at the behavior you want.<br><br>If =
it would be better for a user to hand-write a type-erased type rather than =
use your language-based one, then your language feature has design problems=
..<br><br>Is not the whole point of this feature to make type-erasure a firs=
t-class part of the language? If so, then it needs to be usable by <i>every=
one</i> who wants to use type-erasure, not just everyone who wants referenc=
e semantics. Concepts doesn&#39;t have this flaw; if you want to pass a val=
ue that satisfies a concept around by value, you can (so long as the concep=
t allows such copying/moving).<br><br>Why can&#39;t proxies?<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><font face=3D"=
georgia, serif">P.S. It is possible for a proxy to proxy any type, includin=
g member functions, as long as=C2=A0they are not temporary variables:</font=
></div><div><font face=3D"georgia, serif"><div style=3D"border:1px solid rg=
b(187,187,187);word-wrap:break-word;background-color:rgb(250,250,250)"><cod=
e><div><div>auto f =3D std::bind(...);</div><div>Runnable r(f);</div></div>=
</code></div></font></div><div><font face=3D"georgia, serif"><br></font></d=
iv></div></blockquote><div><br>But now you have to make sure that `f` stays=
 alive so long as `r` does. With regular function pointers, you don&#39;t h=
ave to care; function pointers are valid forever. As are member pointers, b=
ut those don&#39;t work here.<br><br>If you were to write a hand-written `R=
unnable&lt;Func&gt;` type, even if it only has reference semantics, you wou=
ld still give it native support for member pointers. Because those are genu=
ine &quot;runnables&quot; and should have first-class access like function =
pointers.<br><br></div></div></blockquote><div><font face=3D"georgia, serif=
">That is why I think the &quot;proxies&quot; should be a language feature =
and the &quot;wrappers&quot; should be a library feature. Wrappers are not =
proxies, they are bound from a proxy and a user-defined implementations, so=
 they should not have semantics like the &quot;proxies&quot;. This is simil=
ar with the reason why std::reference_wrapper do not have the semantics as =
the wrapped object has.</font></div><div>=C2=A0</div><blockquote class=3D"g=
mail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc sol=
id;padding-left: 1ex;"><div dir=3D"ltr"><div>So again, I find myself saying=
 that if hand-written type-erased types are better than your language-based=
 ones, then your language feature has design problems.</div></div></blockqu=
ote></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/4376b734-9a95-46d5-af3e-0aba3e722501%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/4376b734-9a95-46d5-af3e-0aba3e722501=
%40isocpp.org</a>.<br />

------=_Part_781_402921243.1494742301841--

------=_Part_780_1639054629.1494742301841--

.


Author: Jakob Riedle <jakob.riedle@gmail.com>
Date: Sun, 14 May 2017 08:40:17 -0700 (PDT)
Raw View
------=_Part_973_2066666570.1494776417607
Content-Type: multipart/alternative;
 boundary="----=_Part_974_1333044172.1494776417607"

------=_Part_974_1333044172.1494776417607
Content-Type: text/plain; charset="UTF-8"

Hi Folks,

I really have the feeling, that this discussion is not leading somewhere
helpful anymore.
The challanges a proposal has to face have been outlined very clearly now
by the participants of this thread.

Personally, I find it to be quite hard to argue about something that is not
yet specified to at least 60%.
Even if several concerns seem to be quite applicable, it is up to *a
proposal *to give answers to them.
This thread is IMO not the right spot to work out solutions for every
single detail but rather to identify spots of potential need for
clarification.

Therefore I rather suggest someone to write a proposal.

Jakob


PS: If nobody wants to do that, I'd be glad to do that myself!

--
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/6f0f7ed7-e7e1-40fb-b783-ccb3a58344a6%40isocpp.org.

------=_Part_974_1333044172.1494776417607
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Hi Folks,=C2=A0<div><br></div><div>I really have the feeli=
ng, that this discussion is not leading somewhere helpful anymore.</div><di=
v>The challanges a proposal has to face have been outlined very clearly now=
 by the participants of this thread.</div><div><br></div><div>Personally, I=
 find it to be quite hard to argue about something that is not yet specifie=
d to at least 60%.</div><div>Even if several concerns seem to be quite appl=
icable, it is up to <b>a proposal=C2=A0</b>to give answers to them.</div><d=
iv>This thread is IMO not the right spot to work out solutions for every si=
ngle detail but rather to identify spots of potential need for clarificatio=
n.</div><div><br></div><div>Therefore I rather suggest someone to write a p=
roposal.</div><div><br></div><div>Jakob</div><div><br></div><div><br></div>=
<div>PS: If nobody wants to do that, I&#39;d be glad to do that myself!</di=
v></div>

<p></p>

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

------=_Part_974_1333044172.1494776417607--

------=_Part_973_2066666570.1494776417607--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 14 May 2017 11:00:49 -0700 (PDT)
Raw View
------=_Part_1057_2070860347.1494784850013
Content-Type: multipart/alternative;
 boundary="----=_Part_1058_584268934.1494784850013"

------=_Part_1058_584268934.1494784850013
Content-Type: text/plain; charset="UTF-8"

On Sunday, May 14, 2017 at 2:11:41 AM UTC-4, Mingxin Wang wrote:
>
> On Sunday, May 14, 2017 at 10:56:16 AM UTC+8, Nicol Bolas wrote:
>>
>> On Saturday, May 13, 2017 at 10:24:29 PM UTC-4, Mingxin Wang wrote:
>>>
>>> Dear Mr. Bengt Gustafsson and Mr. Nicol Bolas,
>>>
>>> Thank you for your ideas.
>>>
>>> Such requirements really do exist! But I think this is more appropriate
>>> to be a library feature rather than a lanuage feature to *bind* a value
>>> to a proxy. I have just built a "Wrapper" class, as is shown below:
>>>
>>>
>> [...]
>>>
>>
>>>
>> *With this class, it is possible to use "Wrapper<SomeProxy>" to turn a
>>> proxy into a value wrapper.* But as it is a wrapper (like
>>> "std::reference_wrapper" does), certain member functions are provided to
>>> access the proxy ("get()" and "operator P&").
>>>
>>> I think this is enough so far.
>>>
>>
>> The deficiencies relative to a hand-written type-erased type are readily
>> apparent:
>>
>> 1) The wrapper takes up more memory.
>>
>
> On my compiler (G++ 6.3.0 x64):
>
> sizeof(std::function<void()>) == 32;
> sizeof(Wrapper<Runnable>) == 24;
>
>
This is an apples-to-oranges comparison. Your `Wrapper` implementation
doesn't use small storage optimization (SSO), but `function` almost
certainly does (as evidenced by your performance tests). If you used a
`function` implementation that didn't use SSO, then you'll find that it
could just be `sizeof(void*)` in size; *maybe* `2 * sizeof(void*)`,
depending on implementation. By contrast, `Wrapper` cannot possibly get any
smaller.

Now, if you implemented `Wrapper` to have an equivalent SSO buffer to that
of `function`, then you would again find that `function` is smaller. Why?
An equivalent SSO-based `Wrapper` implementation would have the same
internal buffer needs as an SSO `function` implementation. But because
`Wrapper` also stores a proxy object, it would need a proxy member
subobject in addition to that storage. So whatever the `function`'s size
is, an SSO `Wrapper` would need `sizeof(Proxy)` more bytes to have
equivalent SSO storage.

There's no way around this; whatever proxy wrapper you use will *always*
take more space than an *equivalent* `function` implementation.

2) The wrapper is less efficient (since it has two type-erasures instead of
>> just one).
>>
>
> To test the performance of the wrapper,
>

I wasn't specifically talking about being faster or slower. I said it was
"less efficient". Two type-erasures means two vtables. This means two
vtables for every type you erase.

The wrapper will result in more code generation than `function`. Again,
there's no way around this. How important that is differs from person to
person, but it's an inefficient that doesn't *have to exist*.


> I did a little experiment on my PC (with G++ 6.3.0 x64, Command line: g++
> -march=corei7-avx -O2 -Wall -std=c++17):
> <snip>
> The result is shown in the table below:
>
>
> <https://lh3.googleusercontent.com/-b7s_rR8iY9o/WRfuXWeINII/AAAAAAAAAEs/VnaF4_GJmO4Xgt6X185BDyDHtV0XOjq9QCLcB/s1600/%25E5%259B%25BE%25E7%2589%25871.png>
>
> It is not surprising that std::function<void> is much efficient than
> Wrapper<Runnable> with small data sets (after compiler optimizations we
> have), because it has been specially constructed.
>

Please read what you just wrote. You wrote that a hand-written type-erased
type will be faster in many cases than your wrapper. I don't understand how
you can write that and still think your design decision is a good idea.

Look at classes. When they made virtual functions, they didn't define it in
such a way that hand-coded vtables would be *faster* than
compiler-generated ones. Because that would be a *huge defect* in the
language, since it would encourage people *not to use the feature*. If
people decide to *avoid* using a language feature because it's slower than
doing the same thing manually, that's a serious deficiency in that language
feature (see the performance issues of `dynamic_cast` for an example).

There is no reason why the compiler would be unable to generate a value
semantics Runnable proxy that was as efficient or moreso than
`std::function`. The reason it doesn't work here is because your `Wrapper`
type is not a *language feature*; it's a library construct. And therefore
it has to play by the rules of library constructs rather than language
features.

By making it a library construct, you have *denied* the compiler the power
it needs in order to generate the code that it could have.

But as you can see from the table, Wrapper<Runnable> is a little more
> efficient than std::function<void> with large data sets. Besides,
> Wrapper<T> is just a descriptive implementation, compiler vendors may apply
> other algorithms to reach a compromise if necessary.
>

Unless you have certain knowledge that implementations of `wrapper<T>`
actually can "apply other algorithms to reach such a compromise", then you
should not dismiss such criticism.

Especially since `wrapper<T>` still has plenty of other criticisms, as I've
outlined.

P.S. It is possible for a proxy to proxy any type, including member
>>> functions, as long as they are not temporary variables:
>>> auto f = std::bind(...);
>>> Runnable r(f);
>>>
>>>
>> But now you have to make sure that `f` stays alive so long as `r` does.
>> With regular function pointers, you don't have to care; function pointers
>> are valid forever. As are member pointers, but those don't work here.
>>
>> If you were to write a hand-written `Runnable<Func>` type, even if it
>> only has reference semantics, you would still give it native support for
>> member pointers. Because those are genuine "runnables" and should have
>> first-class access like function pointers.
>>
>> That is why I think the "proxies" should be a language feature and the
> "wrappers" should be a library feature. Wrappers are not proxies, they are
> bound from a proxy and a user-defined implementations, so they should not
> have semantics like the "proxies". This is similar with the reason why
> std::reference_wrapper do not have the semantics as the wrapped object has.
>

You're effectively defining the problem domain so that value semantics is
not even a question. `reference_wrapper` doesn't have value semantics
because it's called `*reference*_wrapper`. It is, by definition, not the
point of the type.

I'm saying that the feature you're talking about is *really* "language
support for type-erasure". And that feature *does not* define itself by
creating reference wrappers. So there's nothing to be gained by *preventing*
"language support for type-erasure" from providing value semantics, where a
user wants it. Language support for value-semantics type-erasure is
superior in *every way* to your "wrapper" solution.

While simultaneously not harming the ability to create reference-semantics
type-erasure.

Or to put it another way, how is your feature made better or more effective
at doing its job by *forbidding* value semantics? Because I can't think of
a reason to explicitly disallow people from making type-erasure use value
semantics. Even if you personally would never use a value semantics proxy,
why are you so adamant about *stopping* others from doing so?

It really is like suggesting that lambdas should have always captured
variables by reference, and then saying that you can just write a wrapper
around your reference lambda if you want to store values. That is
technically true, but that doesn't make it a better idea than just allowing
lambdas to capture by copy/move directly.

Just because you *can* get away without something doesn't mean you *should*.
A holistic language feature is better than the minimum you can get away
with + a half-measure for other cases.

--
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/d0154a44-aae6-4e80-a5e9-9cb5312cc5a1%40isocpp.org.

------=_Part_1058_584268934.1494784850013
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Sunday, May 14, 2017 at 2:11:41 AM UTC-4, Mingxin Wang =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On Sund=
ay, May 14, 2017 at 10:56:16 AM UTC+8, Nicol Bolas wrote:<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">On Saturday, May 13, 2017 at 10:24:=
29 PM UTC-4, Mingxin Wang wrote:<blockquote class=3D"gmail_quote" style=3D"=
margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><di=
v dir=3D"ltr"><div><font face=3D"georgia, serif">Dear Mr. Bengt Gustafsson =
and Mr. Nicol Bolas,</font><br></div><div><font face=3D"georgia, serif"><br=
></font></div><div><font face=3D"georgia, serif">Thank you for your ideas.<=
/font></div><div><font face=3D"georgia, serif"><br></font></div><div><font =
face=3D"georgia, serif">Such requirements really do exist! But I think this=
 is more appropriate to be a library feature rather than a lanuage feature =
to <b>bind</b> a value to a proxy. I have just built a &quot;Wrapper&quot; =
class, as is shown below:</font></div><div>=C2=A0</div></div></blockquote><=
blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border=
-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div></div><div>[..=
..]<br></div></div></blockquote><blockquote class=3D"gmail_quote" style=3D"m=
argin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left=
:1ex"><div>=C2=A0</div></blockquote><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr"><div><font face=3D"georgia, serif"><b>With this class, it=
 is possible to use &quot;Wrapper&lt;SomeProxy&gt;&quot; to turn a proxy in=
to a value wrapper.</b> But as it is a wrapper (like &quot;std::reference_w=
rapper&quot; does), certain member functions are provided to access the pro=
xy (&quot;get()&quot; and &quot;operator P&amp;&quot;).</font></div><div><f=
ont face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, se=
rif">I think this is enough so far.</font></div></div></blockquote><div><br=
>The deficiencies relative to a hand-written type-erased type are readily a=
pparent:<br><br>1) The wrapper takes up more memory.</div></div></blockquot=
e><div><br></div><div><font face=3D"georgia, serif">On my compiler (G++ 6.3=
..0 x64):</font></div><div><br></div><div><div style=3D"border:1px solid rgb=
(187,187,187);word-wrap:break-word;background-color:rgb(250,250,250)"><code=
><div><font face=3D"courier new, monospace"><div style=3D"background-color:=
rgb(255,255,255)"><span style=3D"color:#008">sizeof</span><span style=3D"co=
lor:#660">(</span><span style=3D"color:#000">std</span><span style=3D"color=
:#660">::</span><span style=3D"color:#008">function</span><span style=3D"co=
lor:#660">&lt;</span><span style=3D"color:#008">void</span><span style=3D"c=
olor:#660">()&gt;)</span><span style=3D"color:#000"> </span><span style=3D"=
color:#660">=3D=3D</span><span style=3D"color:#000"> </span><span style=3D"=
color:#066">32</span><span style=3D"color:#660">;</span></div><div style=3D=
"background-color:rgb(255,255,255)"><span style=3D"color:#008">sizeof</span=
><span style=3D"color:#660">(</span><span style=3D"color:#606">Wrapper</spa=
n><span style=3D"color:#660">&lt;</span><span style=3D"color:#606">Runnable=
</span><span style=3D"color:#660">&gt;)</span><span style=3D"color:#000"> <=
/span><span style=3D"color:#660">=3D=3D</span><span style=3D"color:#000"> <=
/span><span style=3D"color:#066">24</span><span style=3D"color:#660">;</spa=
n></div></font></div></code></div></div><div><br></div></div></blockquote><=
div><br>This is an apples-to-oranges comparison. Your `Wrapper` implementat=
ion doesn&#39;t use small storage optimization (SSO), but `function` almost=
 certainly does (as evidenced by your performance tests). If you used a `fu=
nction` implementation that didn&#39;t use SSO, then you&#39;ll find that i=
t could just be `sizeof(void*)` in size; <i>maybe</i> `2 * sizeof(void*)`, =
depending on implementation. By contrast, `Wrapper` cannot possibly get any=
 smaller.<br><br>Now, if you implemented `Wrapper` to have an equivalent SS=
O buffer to that of `function`, then you would again find that `function` i=
s smaller. Why? An equivalent SSO-based `Wrapper` implementation would have=
 the same internal buffer needs as an SSO `function` implementation. But be=
cause `Wrapper` also stores a proxy object, it would need a proxy member su=
bobject in addition to that storage. So whatever the `function`&#39;s size =
is, an SSO `Wrapper` would need `sizeof(Proxy)` more bytes to have equivale=
nt SSO storage.<br><br>There&#39;s no way around this; whatever proxy wrapp=
er you use will <i>always</i> take more space than an <i>equivalent</i> `fu=
nction` implementation.<br><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 dir=3D"ltr"><div></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr"><div>2) The wrapper is less efficient (since it has two t=
ype-erasures instead of just one).<br></div></div></blockquote><div><br></d=
iv><div><font face=3D"georgia, serif">To test the performance of the wrappe=
r,</font></div></div></blockquote><div><br>I wasn&#39;t specifically talkin=
g about being faster or slower. I said it was &quot;less efficient&quot;. T=
wo type-erasures means two vtables. This means two vtables for every type y=
ou erase.<br><br>The wrapper will result in more code generation than `func=
tion`. Again, there&#39;s no way around this. How important that is differs=
 from person to person, but it&#39;s an inefficient that doesn&#39;t <i>hav=
e to exist</i>.<br>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"m=
argin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"=
><div dir=3D"ltr"><div><font face=3D"georgia, serif">I did a little experim=
ent on my PC (with G++ 6.3.0 x64, Command line: g++ -march=3Dcorei7-avx -O2=
 -Wall -std=3Dc++17):</font></div>&lt;snip&gt;<br><div><font face=3D"georgi=
a, serif">The result is shown in the table below:</font></div><div><p style=
=3D"text-align:center;clear:both"><a href=3D"https://lh3.googleusercontent.=
com/-b7s_rR8iY9o/WRfuXWeINII/AAAAAAAAAEs/VnaF4_GJmO4Xgt6X185BDyDHtV0XOjq9QC=
LcB/s1600/%25E5%259B%25BE%25E7%2589%25871.png" style=3D"margin-left:1em;mar=
gin-right:1em" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=
=3D&#39;https://lh3.googleusercontent.com/-b7s_rR8iY9o/WRfuXWeINII/AAAAAAAA=
AEs/VnaF4_GJmO4Xgt6X185BDyDHtV0XOjq9QCLcB/s1600/%25E5%259B%25BE%25E7%2589%2=
5871.png&#39;;return true;" onclick=3D"this.href=3D&#39;https://lh3.googleu=
sercontent.com/-b7s_rR8iY9o/WRfuXWeINII/AAAAAAAAAEs/VnaF4_GJmO4Xgt6X185BDyD=
HtV0XOjq9QCLcB/s1600/%25E5%259B%25BE%25E7%2589%25871.png&#39;;return true;"=
><img src=3D"https://lh3.googleusercontent.com/-b7s_rR8iY9o/WRfuXWeINII/AAA=
AAAAAAEs/VnaF4_GJmO4Xgt6X185BDyDHtV0XOjq9QCLcB/s400/%25E5%259B%25BE%25E7%25=
89%25871.png" width=3D"400" height=3D"50" border=3D"0"></a></p><div style=
=3D"text-align:left"><br></div><div style=3D"text-align:left"><font face=3D=
"georgia, serif">It is not=C2=A0surprising that std::function&lt;void&gt; i=
s much efficient than Wrapper&lt;Runnable&gt; with small data sets (after c=
ompiler optimizations we have), because it has been specially constructed.<=
/font></div></div></div></blockquote><div><br>Please read what you just wro=
te. You wrote that a hand-written type-erased type will be faster in many c=
ases than your wrapper. I don&#39;t understand how you can write that and s=
till think your design decision is a good idea.<br><br>Look at classes. Whe=
n they made virtual functions, they didn&#39;t define it in such a way that=
 hand-coded vtables would be <i>faster</i> than compiler-generated ones. Be=
cause that would be a <i>huge defect</i> in the language, since it would en=
courage people <i>not to use the feature</i>. If people decide to <i>avoid<=
/i> using a language feature because it&#39;s slower than doing the same th=
ing manually, that&#39;s a serious deficiency in that language feature (see=
 the performance issues of `dynamic_cast` for an example).<br><br>There is =
no reason why the compiler would be unable to generate a value semantics Ru=
nnable proxy that was as efficient or moreso than `std::function`. The reas=
on it doesn&#39;t work here is because your `Wrapper` type is not a <i>lang=
uage feature</i>; it&#39;s a library construct. And therefore it has to pla=
y by the rules of library constructs rather than language features.<br><br>=
By making it a library construct, you have <i>denied</i> the compiler the p=
ower it needs in order to generate the code that it could have.<br><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div s=
tyle=3D"text-align:left"><font face=3D"georgia, serif">But as you can see f=
rom the table, Wrapper&lt;Runnable&gt; is a little more efficient than std:=
:function&lt;void&gt; with large data sets. Besides, Wrapper&lt;T&gt; is ju=
st a=C2=A0descriptive implementation, compiler vendors may apply other algo=
rithms to reach a compromise if necessary.</font></div></div></div></blockq=
uote><div><br>Unless you have certain knowledge that implementations of `wr=
apper&lt;T&gt;` actually can &quot;apply other algorithms to reach such a c=
ompromise&quot;, then you should not dismiss such criticism.<br><br>Especia=
lly since `wrapper&lt;T&gt;` still has plenty of other criticisms, as I&#39=
;ve outlined.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margi=
n: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><di=
v dir=3D"ltr"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=
=3D"ltr"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;mar=
gin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr=
"><div><font face=3D"georgia, serif">P.S. It is possible for a proxy to pro=
xy any type, including member functions, as long as=C2=A0they are not tempo=
rary variables:</font></div><div><font face=3D"georgia, serif"><div style=
=3D"border:1px solid rgb(187,187,187);word-wrap:break-word;background-color=
:rgb(250,250,250)"><code><div><div>auto f =3D std::bind(...);</div><div>Run=
nable r(f);</div></div></code></div></font></div><div><font face=3D"georgia=
, serif"><br></font></div></div></blockquote><div><br>But now you have to m=
ake sure that `f` stays alive so long as `r` does. With regular function po=
inters, you don&#39;t have to care; function pointers are valid forever. As=
 are member pointers, but those don&#39;t work here.<br><br>If you were to =
write a hand-written `Runnable&lt;Func&gt;` type, even if it only has refer=
ence semantics, you would still give it native support for member pointers.=
 Because those are genuine &quot;runnables&quot; and should have first-clas=
s access like function pointers.<br><br></div></div></blockquote><div><font=
 face=3D"georgia, serif">That is why I think the &quot;proxies&quot; should=
 be a language feature and the &quot;wrappers&quot; should be a library fea=
ture. Wrappers are not proxies, they are bound from a proxy and a user-defi=
ned implementations, so they should not have semantics like the &quot;proxi=
es&quot;. This is similar with the reason why std::reference_wrapper do not=
 have the semantics as the wrapped object has.</font></div></div></blockquo=
te><div><br>You&#39;re effectively defining the problem domain so that valu=
e semantics is not even a question. `reference_wrapper` doesn&#39;t have va=
lue semantics because it&#39;s called `<i>reference</i>_wrapper`. It is, by=
 definition, not the point of the type.<br><br>I&#39;m saying that the feat=
ure you&#39;re talking about is <i>really</i> &quot;language support for ty=
pe-erasure&quot;. And that feature <i>does not</i> define itself by creatin=
g reference wrappers. So there&#39;s nothing to be gained by <i>preventing<=
/i> &quot;language support for type-erasure&quot; from providing value sema=
ntics, where a user wants it. Language support for value-semantics type-era=
sure is superior in <i>every way</i> to your &quot;wrapper&quot; solution.<=
br><br>While simultaneously not harming the ability to create reference-sem=
antics type-erasure.<br><br>Or to put it another way, how is your feature m=
ade better or more effective at doing its job by <i>forbidding</i> value se=
mantics? Because I can&#39;t think of a reason to explicitly disallow peopl=
e from making type-erasure use value semantics. Even if you personally woul=
d never use a value semantics proxy, why are you so adamant about <i>stoppi=
ng</i> others from doing so?<br><br>It really is like suggesting that lambd=
as should have always captured variables by reference, and then saying that=
 you can just write a wrapper around your reference lambda if you want to s=
tore values. That is technically true, but that doesn&#39;t make it a bette=
r idea than just allowing lambdas to capture by copy/move directly.<br><br>=
Just because you <i>can</i> get away without something doesn&#39;t mean you=
 <i>should</i>. A holistic language feature is better than the minimum you =
can get away with + a half-measure for other cases.</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/d0154a44-aae6-4e80-a5e9-9cb5312cc5a1%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d0154a44-aae6-4e80-a5e9-9cb5312cc5a1=
%40isocpp.org</a>.<br />

------=_Part_1058_584268934.1494784850013--

------=_Part_1057_2070860347.1494784850013--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sun, 14 May 2017 15:05:57 -0700 (PDT)
Raw View
------=_Part_1141_188473939.1494799557321
Content-Type: multipart/alternative;
 boundary="----=_Part_1142_210246601.1494799557321"

------=_Part_1142_210246601.1494799557321
Content-Type: text/plain; charset="UTF-8"

Note: In this text I start by introducing a feature not entirely related to
the matter at hand. However, there is a plot twist at
the end which explains it all!

Indirect ineheritance
=====================

It is sometimes needed to re-implement an API of another class, such as
when implementing type erasure. C++ currently contains one
way of reusing an API, inheritance. Unforunately inheritance implies a by
value instance of the base class which prevents the
polymorphism central to the type erasure technique. To remedy this
situation I have explored an idea of "indirect inheritance" on a
cursory level.  By indirect inheritance I mean that the base class part is
separated (in memory) from the subclass part and its
location is instead specified by other means. After some consideration it
seems that the best such "means" is a member function,
which I will call the *indirection function*. This function provides the
necessary flexibility to implement different types of type
erased class templates with different lifetime management strategies which
was hard to achieve with alternate approaches.

Example:
--------

// General handle class with shared ownership.
    template<typename T> class shared_proxy : public T(getPtr) {
    public:
shared_prioxy(const shared_ptr<T>& src) : mPtr(src) {}
    private:
T& getPtr() { return *mPtr; }
const T& getPtr() const { return *mPtr; }

        shared_ptr<T> mPtr;
    };

This code looks pretty ordinary and it is obvious that shared_proxy<T>
implements the API of T as it inherits from it. What's special
with this code is of course the specification of a method name as
"parameter" to the base class T. This is what indicates
indirect inheritance and specifies how the `this` pointer for the T base
class is to be retrieved.

The actual type erasing consists of the possibility to initiate a
shared_proxy<T> with any subclass of T. This offers
some convenience over a plain shared_ptr in that its members can be
accessed using . instead of -> and that it can be an operand
of function calls or operators without using the * indirection operator.

However, it is almost as easy to create generic by value type erasure,
albeit now we have to handle the deleter functionality
(equvalent of the shared_ptr control block), SOO optimization etc. This is
a major step in convenience and offers an alternate way
of achieving most of the goals of the proposed operator.():

Example:
--------

    template<typename T> class value_proxy : public T(getPtr) {
    public:
template<typename U> value_proxy(U& src) : mPtr(std::make_deep<U>(src)) {}

    private:
T& getPtr() { return *mPtr; }
const T& getPtr() const { return *mPtr; }

        deep_ptr<T> mPtr;
    };

Sub sub;

void fun(const value_proxy<Base>& par);

// Call fun with subclass object. This creates a hidden copy refered by the
deep_ptr which fun can use and store freely. Still
    // retaining the original Sub quality of it.
fun(sub);


Here I use a fictituous deep_ptr which has the ability to clone its pointee
when it itself is copied. Implementing it gets messy but that's
another story...

The compiler generates code at each use of a T member to first call the
indirection function and use
the returned T& value as the this pointer for the base class. Any decent
optimizer will then reduce this to just an unavoidable pointer
indirection, creating, as far as I can see, an optimal implementation from
both memory use and runtime aspects, i.e. identical as a
shared_ptr or deep_ptr itself in these cases.

When the object is used as a parameter to a function or operator taking a
T& the compiler must realize that the T of the proxy is
reached via the indirection function and call it, giving the returned
pointer to the function or operator to be called.

It is possible to allow the indirection function to return a const T& and
then only const methods are
accessible and only const access to members would be allowed (just as
expected). As seen in the examples it is allowed to overload
the indirection function for const/non-const proxy object which enables the
constness of the base class to follow the constness of the
proxy object which is probably desired in most cases. Thus the "paremeter"
of the type is to be considered a name of an overload
set rather than a method pointer.


Duck typing indirect inheritance
================================

Given the indirect inheritance feature it is not entirely far fetched to
extend it to handle the cases discussed in this thread,
that is, when the T and U classes of a value_proxy are not related by
inheritance. This places some additional requirements on the
design. Firstly there must be a hidden function/offset table to map between
function addresses and member offsets of T and U.
Secondly the code that calls the functions or accesses the data members
must be augented similarly. Thirdly there must be some
syntax to indicate the U type at hand in the constructor call. For now I
will use a simple but odd T(U) syntax in the base/member
initializer list.

As for the indirection function there is a choice of still mandating that
it return a T& or to allow it
to return void*. I think the latter is more appropriate as there would have
to be void* types involved anyway, due to the lack of
common base class.

The boilerplate in the proxy object becomes a bit more complicated when
there is no common base class but the usual trick of in
place constructing an object with virtual destruct and clone methods makes
this work. In this example I assume that a
deep_ptr<void> specialization is available which implements this for us:


    template<typename T> class proxy : public T(getPtr) {
    public:
template<typename U> proxy(U& src) : T(U), mPtr(std::make_deep<void>(src))
{}

    private:
void* getPtr() { return *mPtr; }
const void* getPtr() const { return *mPtr; }

        deep_ptr<void> mPtr;
    };

struct First {
void func(int, float);
int x;
    };

struct Second {
void func(int, float);
int y;
int x;
    };

Second sec;

void fun(const proxy<First>& par);

// Call fun with duck typed `Second` object. This creates a hidden copy
refered by the deep_ptr<void> which fun can use and store freely. Still
    // retaining the original `First` quality of it.

proxy<First> pf = Sec;
pf.func(1, 3.14); // Calls Second.func.

fun(sec); // Implicitly converts sec to a proxy object.


The compiler uses First to create a function/offset table layout when it
sees the first proxy<First>. When it sees the constructor
call proxy<First>::proxy<Second>() at the initialization of pf it creates
an instance (during compile time) of this table layout
containing the corresponding method addresses and member offsets for Second.

The T base class now consumes space for one pointer to store the address of
the function/offset table and this gets set to the
appropriate table by the code generated for the specific template
constructor.

When the duck typed base class methods are called the compiler must
generate not only the call to the indirection function, but
also defer the actual function call via the function/offset table just like
a virtual function call. Even if the method in T
itself is virtual I don't think we should require two level dispatch, which
would be needed if the constructor parameter to proxy
is really a reference to a subclass of U. This is as cloning the object
using the helper object created for the class U would still
slice the object, so this construct will still require that the ctor sees
the actual type of the provided instance. This is the same
problem as with deep_ptr itself, as debated in another thread. On the other
hand this slicing would not occur for by-reference
proxies. Possibly both policies can be allowed by adorning the base class
name with a modifier such as virtual (although this has
totally different meaning than for current virtual bases).

At each access to a data member an offset from the function/offset pointer
table would have to be added to the return value of the
indirection function instead of just adding a fixed offset to this for
normal data member access. This is an unavoidable overhead
for the type erasure.

There seems to be no way that the proxy<T> can behave as a T when used as a
by reference or by pointer function or operator
operand. This is of course due to the fact that there is actually no T
object to refer to. While this is unfortunate it seems
impossible to avoid so the only remedy would be to let those functions and
operators take proxy<T>& as parameter, with the
associated runtime penalty, or make them templates (taking T or proxy<T>)
with the associated compile time/object size cost. I
think this the major drawback of this entire idea, as it gets hard to teach
and limits the usefulness.

--
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/1b64712a-d9d5-4e93-82fd-1dfd2c5eddcf%40isocpp.org.

------=_Part_1142_210246601.1494799557321
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Note: In this text I start by introducing a feature n=
ot entirely related to the matter at hand. However, there is a plot twist a=
t</div><div>the end which explains it all!</div><div><br></div><div>Indirec=
t ineheritance</div><div>=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D</div><div><br></div><div>It is sometimes needed to re-imple=
ment an API of another class, such as when implementing type erasure. C++ c=
urrently contains one</div><div>way of reusing an API, inheritance. Unforun=
ately inheritance implies a by value instance of the base class which preve=
nts the</div><div>polymorphism central to the type erasure technique. To re=
medy this situation I have explored an idea of &quot;indirect inheritance&q=
uot; on a</div><div>cursory level. =C2=A0By indirect inheritance I mean tha=
t the base class part is separated (in memory) from the subclass part and i=
ts</div><div>location is instead specified by other means. After some consi=
deration it seems that the best such &quot;means&quot; is a member function=
,</div><div>which I will call the *indirection function*. This function pro=
vides the necessary flexibility to implement different types of type</div><=
div>erased class templates with different lifetime management strategies wh=
ich was hard to achieve with alternate approaches.</div><div><br></div><div=
>Example:</div><div>--------</div><div><br></div><div><span style=3D"white-=
space:pre"> </span>// General handle class with shared ownership.</div><div=
>=C2=A0 =C2=A0 template&lt;typename T&gt; class shared_proxy : public T(get=
Ptr) {</div><div>=C2=A0 =C2=A0 public:</div><div><span style=3D"white-space=
:pre">  </span>shared_prioxy(const shared_ptr&lt;T&gt;&amp; src) : mPtr(src=
) {}</div><div><span style=3D"white-space:pre">  </span></div><div>=C2=A0 =
=C2=A0 private:</div><div><span style=3D"white-space:pre">  </span>T&amp; g=
etPtr() { return *mPtr; }</div><div><span style=3D"white-space:pre">  </spa=
n>const T&amp; getPtr() const { return *mPtr; }</div><div><br></div><div>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 shared_ptr&lt;T&gt; mPtr;</div><div>=C2=A0 =C2=
=A0 };</div><div><br></div><div>This code looks pretty ordinary and it is o=
bvious that shared_proxy&lt;T&gt; implements the API of T as it inherits fr=
om it. What&#39;s special</div><div>with this code is of course the specifi=
cation of a method name as &quot;parameter&quot; to the base class T. This =
is what indicates</div><div>indirect inheritance and specifies how the `thi=
s` pointer for the T base class is to be retrieved.</div><div><br></div><di=
v>The actual type erasing consists of the possibility to initiate a shared_=
proxy&lt;T&gt; with any subclass of T. This offers</div><div>some convenien=
ce over a plain shared_ptr in that its members can be accessed using . inst=
ead of -&gt; and that it can be an operand</div><div>of function calls or o=
perators without using the * indirection operator.</div><div><br></div><div=
>However, it is almost as easy to create generic by value type erasure, alb=
eit now we have to handle the deleter functionality</div><div>(equvalent of=
 the shared_ptr control block), SOO optimization etc. This is a major step =
in convenience and offers an alternate way</div><div>of achieving most of t=
he goals of the proposed operator.():</div><div><br></div><div>Example:</di=
v><div>--------</div><div><br></div><div>=C2=A0 =C2=A0 template&lt;typename=
 T&gt; class value_proxy : public T(getPtr) {</div><div>=C2=A0 =C2=A0 publi=
c:</div><div><span style=3D"white-space:pre">  </span>template&lt;typename =
U&gt; value_proxy(U&amp; src) : mPtr(std::make_deep&lt;U&gt;(src)) {}</div>=
<div><br></div><div>=C2=A0 =C2=A0 private:</div><div><span style=3D"white-s=
pace:pre">  </span>T&amp; getPtr() { return *mPtr; }</div><div><span style=
=3D"white-space:pre">  </span>const T&amp; getPtr() const { return *mPtr; }=
</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 deep_ptr&lt;T&gt; mPt=
r;</div><div>=C2=A0 =C2=A0 };</div><div><br></div><div><span style=3D"white=
-space:pre"> </span>Sub sub;</div><div><br></div><div><span style=3D"white-=
space:pre"> </span>void fun(const value_proxy&lt;Base&gt;&amp; par);</div><=
div><br></div><div><span style=3D"white-space:pre"> </span>// Call fun with=
 subclass object. This creates a hidden copy refered by the deep_ptr which =
fun can use and store freely. Still</div><div>=C2=A0 =C2=A0 // retaining th=
e original Sub quality of it.</div><div><span style=3D"white-space:pre"> </=
span>fun(sub);<span style=3D"white-space:pre">  </span></div><div><br></div=
><div><br></div><div>Here I use a fictituous deep_ptr which has the ability=
 to clone its pointee when it itself is copied. Implementing it gets messy =
but that&#39;s</div><div>another story...</div><div><br></div><div>The comp=
iler generates code at each use of a T member to first call the indirection=
 function and use</div><div>the returned T&amp; value as the this pointer f=
or the base class. Any decent optimizer will then reduce this to just an un=
avoidable pointer</div><div>indirection, creating, as far as I can see, an =
optimal implementation from both memory use and runtime aspects, i.e. ident=
ical as a</div><div>shared_ptr or deep_ptr itself in these cases.</div><div=
><br></div><div>When the object is used as a parameter to a function or ope=
rator taking a T&amp; the compiler must realize that the T of the proxy is<=
/div><div>reached via the indirection function and call it, giving the retu=
rned pointer to the function or operator to be called.</div><div><br></div>=
<div>It is possible to allow the indirection function to return a const T&a=
mp; and then only const methods are</div><div>accessible and only const acc=
ess to members would be allowed (just as expected). As seen in the examples=
 it is allowed to overload</div><div>the indirection function for const/non=
-const proxy object which enables the constness of the base class to follow=
 the constness of the</div><div>proxy object which is probably desired in m=
ost cases. Thus the &quot;paremeter&quot; of the type is to be considered a=
 name of an overload</div><div>set rather than a method pointer.</div><div>=
<br></div><div><br></div><div>Duck typing indirect inheritance</div><div>=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D</div><div><br></div><div>Given the indirect inheritan=
ce feature it is not entirely far fetched to extend it to handle the cases =
discussed in this thread,</div><div>that is, when the T and U classes of a =
value_proxy are not related by inheritance. This places some additional req=
uirements on the</div><div>design. Firstly there must be a hidden function/=
offset table to map between function addresses and member offsets of T and =
U.</div><div>Secondly the code that calls the functions or accesses the dat=
a members must be augented similarly. Thirdly there must be some</div><div>=
syntax to indicate the U type at hand in the constructor call. For now I wi=
ll use a simple but odd T(U) syntax in the base/member</div><div>initialize=
r list.</div><div><br></div><div>As for the indirection function there is a=
 choice of still mandating that it return a T&amp; or to allow it</div><div=
>to return void*. I think the latter is more appropriate as there would hav=
e to be void* types involved anyway, due to the lack of</div><div>common ba=
se class.=C2=A0</div><div><br></div><div>The boilerplate in the proxy objec=
t becomes a bit more complicated when there is no common base class but the=
 usual trick of in</div><div>place constructing an object with virtual dest=
ruct and clone methods makes this work. In this example I assume that a</di=
v><div>deep_ptr&lt;void&gt; specialization is available which implements th=
is for us:</div><div><br></div><div><br></div><div>=C2=A0 =C2=A0 template&l=
t;typename T&gt; class proxy : public T(getPtr) {</div><div>=C2=A0 =C2=A0 p=
ublic:</div><div><span style=3D"white-space:pre">  </span>template&lt;typen=
ame U&gt; proxy(U&amp; src) : T(U), mPtr(std::make_deep&lt;void&gt;(src)) {=
}</div><div><br></div><div>=C2=A0 =C2=A0 private:</div><div><span style=3D"=
white-space:pre">  </span>void* getPtr() { return *mPtr; }</div><div><span =
style=3D"white-space:pre">  </span>const void* getPtr() const { return *mPt=
r; }</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 deep_ptr&lt;void&=
gt; mPtr;</div><div>=C2=A0 =C2=A0 };</div><div><br></div><div><span style=
=3D"white-space:pre"> </span>struct First {</div><div><span style=3D"white-=
space:pre">  </span>void func(int, float);</div><div><span style=3D"white-s=
pace:pre">  </span>int x;</div><div>=C2=A0 =C2=A0 };</div><div><br></div><d=
iv><span style=3D"white-space:pre"> </span>struct Second {</div><div><span =
style=3D"white-space:pre">  </span>void func(int, float);</div><div><span s=
tyle=3D"white-space:pre">  </span>int y;</div><div><span style=3D"white-spa=
ce:pre">  </span>int x;</div><div>=C2=A0 =C2=A0 };</div><div><br></div><div=
><span style=3D"white-space:pre"> </span>Second sec;</div><div><br></div><d=
iv><span style=3D"white-space:pre"> </span>void fun(const proxy&lt;First&gt=
;&amp; par);</div><div><br></div><div><span style=3D"white-space:pre"> </sp=
an>// Call fun with duck typed `Second` object. This creates a hidden copy =
refered by the deep_ptr&lt;void&gt; which fun can use and store freely. Sti=
ll</div><div>=C2=A0 =C2=A0 // retaining the original `First` quality of it.=
</div><div><br></div><div><span style=3D"white-space:pre"> </span>proxy&lt;=
First&gt; pf =3D Sec;</div><div><span style=3D"white-space:pre"> </span>pf.=
func(1, 3.14);<span style=3D"white-space:pre">  </span>// Calls Second.func=
..</div><div><br></div><div><span style=3D"white-space:pre"> </span>fun(sec)=
;<span style=3D"white-space:pre">    </span>// Implicitly converts sec to a=
 proxy object.</div><div><br></div><div><br></div><div>The compiler uses Fi=
rst to create a function/offset table layout when it sees the first proxy&l=
t;First&gt;. When it sees the constructor</div><div>call proxy&lt;First&gt;=
::proxy&lt;Second&gt;() at the initialization of pf it creates an instance =
(during compile time) of this table layout</div><div>containing the corresp=
onding method addresses and member offsets for Second.</div><div><br></div>=
<div>The T base class now consumes space for one pointer to store the addre=
ss of the function/offset table and this gets set to the</div><div>appropri=
ate table by the code generated for the specific template constructor.</div=
><div><br></div><div>When the duck typed base class methods are called the =
compiler must generate not only the call to the indirection function, but</=
div><div>also defer the actual function call via the function/offset table =
just like a virtual function call. Even if the method in T</div><div>itself=
 is virtual I don&#39;t think we should require two level dispatch, which w=
ould be needed if the constructor parameter to proxy</div><div>is really a =
reference to a subclass of U. This is as cloning the object using the helpe=
r object created for the class U would still</div><div>slice the object, so=
 this construct will still require that the ctor sees the actual type of th=
e provided instance. This is the same</div><div>problem as with deep_ptr it=
self, as debated in another thread. On the other hand this slicing would no=
t occur for by-reference</div><div>proxies. Possibly both policies can be a=
llowed by adorning the base class name with a modifier such as virtual (alt=
hough this has</div><div>totally different meaning than for current virtual=
 bases).</div><div><br></div><div>At each access to a data member an offset=
 from the function/offset pointer table would have to be added to the retur=
n value of the</div><div>indirection function instead of just adding a fixe=
d offset to this for normal data member access. This is an unavoidable over=
head</div><div>for the type erasure.</div><div><br></div><div>There seems t=
o be no way that the proxy&lt;T&gt; can behave as a T when used as a by ref=
erence or by pointer function or operator</div><div>operand. This is of cou=
rse due to the fact that there is actually no T object to refer to. While t=
his is unfortunate it seems</div><div>impossible to avoid so the only remed=
y would be to let those functions and operators take proxy&lt;T&gt;&amp; as=
 parameter, with the</div><div>associated runtime penalty, or make them tem=
plates (taking T or proxy&lt;T&gt;) with the associated compile time/object=
 size cost. I</div><div>think this the major drawback of this entire idea, =
as it gets hard to teach and limits the usefulness.</div><div><br></div></d=
iv>

<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/1b64712a-d9d5-4e93-82fd-1dfd2c5eddcf%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/1b64712a-d9d5-4e93-82fd-1dfd2c5eddcf=
%40isocpp.org</a>.<br />

------=_Part_1142_210246601.1494799557321--

------=_Part_1141_188473939.1494799557321--

.


Author: Mingxin Wang <wmx16835vv@163.com>
Date: Mon, 15 May 2017 01:05:00 -0700 (PDT)
Raw View
------=_Part_1273_32354698.1494835500609
Content-Type: multipart/alternative;
 boundary="----=_Part_1274_1929649347.1494835500609"

------=_Part_1274_1929649347.1494835500609
Content-Type: text/plain; charset="UTF-8"

Dear Mr. Bengt Gustafsson,

I think a proxy is something behaves like an ordinary reference (T&, rather
than std::reference_wrapper<T>) with polymorphism, but more flexible than a
reference because

   - a reference can only represent one type, while a proxy can represent
   any type that have specific expressions and semantics, and
   - a proxy has more comprehensive syntax for it is DefaultConstructible,
   CopyConstructible, MoveConstructible, CopyAssignable and MoveAssignable.

With this idea, it is even possible for multiple proxies with different
semantics to represent one object with a little runtime overhead.

But it is relatively difficult for beginners to write C++ code directly
with the proxies, because proxies are not responsible for the life cycle of
the object being represented at all. In order to make it more friendly to
beginners, the class template "Wrapper" is designed, so that users are able
to bind an object with a proxy. With the help of the wrapper that binds an
object with the proxy, on the one hand, users are able to access the
wrapped object with a proxy (with
"Wrapper<SomeProxy>::get()::some_method(...)"), and there is no need to
consider the lifecycle management issue for the wrapped object. On the
other hand it narrows the scope of a proxy's function, meanwhile, may
introduce much runtime overhead for the lifecycle management.

*When it comes to managing the life cycle of a wrapper, I think it is an
issue that has nothing to do with the above.* Users are free to declare a
wrapper as a "stack object" or manage it with a smart pointer, e.g.
"std::unique_ptr<Wrapper<SomeProxy>>" or
"std::shared_ptr<Wrapper<SomeProxy>>", etc.

Mingxin Wang

--
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/86056e1e-28a0-4410-a332-454d50b7b331%40isocpp.org.

------=_Part_1274_1929649347.1494835500609
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><font face=3D"georgia, serif">Dear Mr.=C2=A0Bengt Gustafss=
on,</font><div><font face=3D"georgia, serif"><br></font></div><div><font fa=
ce=3D"georgia, serif">I think a proxy is something behaves like an ordinary=
 reference (T&amp;, rather than std::reference_wrapper&lt;T&gt;) with polym=
orphism, but more flexible than a reference because</font></div><div><ul><l=
i><span style=3D"font-family: georgia, serif;">a reference can only represe=
nt one type, while a proxy can represent any type that have specific expres=
sions and semantics, and</span></li><li><span style=3D"font-family: georgia=
, serif;">a proxy has more comprehensive syntax for it is DefaultConstructi=
ble, CopyConstructible, MoveConstructible, CopyAssignable and MoveAssignabl=
e.</span></li></ul></div><div><span style=3D"font-family: georgia, serif; l=
ine-height: 17px;">With this idea, it is even possible for multiple proxies=
 with different semantics to represent one object with a little runtime ove=
rhead.</span><font face=3D"georgia, serif"><br></font></div><div><font face=
=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, serif">But=
 it is relatively difficult for beginners to write C++ code directly with t=
he proxies, because proxies are not responsible for the life cycle of the o=
bject being represented at all. In order to make it more friendly to beginn=
ers, the class template &quot;Wrapper&quot; is designed, so that users are =
able to bind an object with a proxy. With the help of the wrapper that bind=
s an object with the proxy, on the one hand, users are able to access the w=
rapped object with a proxy (with &quot;Wrapper&lt;SomeProxy&gt;::get()::som=
e_method(...)&quot;), and there is no need to consider the lifecycle manage=
ment issue for the wrapped object. On the other hand it narrows the scope o=
f a proxy&#39;s function, meanwhile, may introduce much runtime overhead fo=
r the lifecycle management.<br></font></div><div><font face=3D"georgia, ser=
if"><br></font></div><div><font face=3D"georgia, serif"><b>When it comes to=
 managing the life cycle of a wrapper, I think it is an issue that has noth=
ing to do with the above.</b> Users are free to declare a wrapper as a &quo=
t;stack object&quot; or manage it with a smart pointer, e.g. &quot;std::uni=
que_ptr&lt;Wrapper&lt;SomeProxy&gt;&gt;&quot; or &quot;std::shared_ptr&lt;W=
rapper&lt;SomeProxy&gt;&gt;&quot;, etc.</font></div><div><font face=3D"geor=
gia, serif"><br></font></div><div><font face=3D"georgia, serif">Mingxin Wan=
g</font></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/86056e1e-28a0-4410-a332-454d50b7b331%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/86056e1e-28a0-4410-a332-454d50b7b331=
%40isocpp.org</a>.<br />

------=_Part_1274_1929649347.1494835500609--

------=_Part_1273_32354698.1494835500609--

.


Author: Bryce Glover <randomdsdevel@gmail.com>
Date: Mon, 15 May 2017 20:12:32 -0400
Raw View
--Apple-Mail=_77AD6C72-BEE0-4652-8961-7EACCDAF02EF
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="UTF-8"

> On May 15, 2017, at 2:22 PM, Bengt Gustafsson <bengt.gustafsson@beamways.=
com> wrote:
>=20
> Den 2017-05-15 kl. 02:55, skrev Bryce Glover:
>>> (snipped=E2=80=A6)
>>=20
>>      Implementing a way to hide the parts of itself that a derived class=
 inherits from its parent base class behind a quasi-opaque, type-erasing =
=E2=80=98pointer to implementation=E2=80=99 from which it could then retrie=
ve this information sounds like it could be interesting and could eventuall=
y end up being useful to somebody, but I=E2=80=99m not entirely certain how=
 well the introduction of such a concept contributes to the discussion unde=
rtaken in this thread so far.
> Well, my intention was for this to become clear towards the end of the po=
st, where the "proxy/interface" version of the indirect inheritance feature=
 is discussed. I already had the indirect inheritance idea back when operat=
or.() was discussed, as an alternative way to implement the handle classes =
it was aiming at. The main problem with operator.() was how to handle the a=
mbiguity if both the handle class and its "T" had a method of the same name=
, which was solved in a tried and true way by viewing this as inheritance (=
i.e. the handle class method takes precedence and hides the T method unless=
 a T:: is prefixed at the call site).
>=20
> When the proxy/interface discussion started it became obvious that the re=
quirements were similar: A template class is to implement the API of its te=
mplate parameter T by some kind of forwarding, but in this case involving a=
 translation table.
>=20
> =E2=80=A6

     Perhaps I=E2=80=99ve just gotten so tired of watching this discussion =
go around in circles even though I haven=E2=80=99t really contributed all t=
hat much to it that my eyes started to glaze over, thus explaining why I di=
dn=E2=80=99t exactly notice how you meant your thoughts to flow when I firs=
t skimmed your description of them.  Rereading your original posting of thi=
s idea to this thread, as well as processing it in light of the additional =
context you=E2=80=99ve just provided here, has, I feel, let me start to cat=
ch on to where you=E2=80=99ve been trying to go with all of this.  I remain=
 somewhat confused, however, as to why you can=E2=80=99t seem to figure out=
 how to cleanly separate the aspect of this mechanism involving a =E2=80=98=
has a=E2=80=99 relationship of type composition (that is, containment) from=
 that related to the =E2=80=98is a=E2=80=99 relationship enforced by inheri=
tance, but I=E2=80=99m starting to appreciate how hard it might turn out to=
 attempt disentangling these two orthogonal properties of a =E2=80=98forwar=
ds to=E2=80=99 relationship when the forwarding object masquerades as its t=
arget object from how you=E2=80=99re explaining things.  Still, I can=E2=80=
=99t help but feel there could be an easier way to cut this Gordian knot de=
spite not knowing how best to present my misgivings on this front. =20

> =E2=80=A6
>=20
> My writeup is an attempt at showing how these two features can be stacked=
 to achieve both goals.
>=20
> =E2=80=A6


     No wonder I felt dizzy, then, what with the number of indirections inv=
olved and all!  I couldn=E2=80=99t keep track of them, as they keep piling =
up!  (Maybe I should just duck back out again and watch those of you with m=
ore expertise in matters like these hash things out, now that I think about=
 it=E2=80=A6)  In any case, t=E2=80=99d probably understand your proposal f=
or how virtual concepts should work if you presented it separately from thi=
s `operator .()`-related =E2=80=98indirect inheritance idea, if asking you =
to do that is in any way a reasonable request. =20

> =E2=80=A6
>=20
> Admittedly my approach is fairly different from the original proposer's w=
ho appointed the "magic features" to the new type of "thing" he called inte=
rface or proxy, while in my approach this declaration is just a regular str=
uct/class declaration and the magic is in the indirect inheritance declarat=
ion.
>=20
> =E2=80=A6


     It reduces the surface area of the new functionality required to imple=
ment language-level type erasure, though, so that=E2=80=99s good. =20

> =E2=80=A6
>=20
>>  Perhaps one could implement a fully functional run-time concept wrapper=
 implementing properly forwarding versions of the functionality expected of=
 the type of objects the compile-time concept associated with this wrapper =
would require it to contain using this technique, but I feel both that a ru=
n-time concept facility should be easy to use by language users with abilit=
ies nearer to beginner level than this particular iteration of this constru=
ct and that said iteration doesn=E2=80=99t feel quite right to me when it c=
omes to usability and understandability, but you should probably trust othe=
r peoples=E2=80=99 reactions more than mine on this front, as I=E2=80=99m n=
ot the best person to give feedback on these kinds of matters.  In any case=
, it strikes me that a version of this =E2=80=98indirect inheritance=E2=80=
=99 that one might consider more acceptably traditional would involve class=
es satisfying concepts related by subsumption, but that doesn=E2=80=99t rea=
lly describe the model you=E2=80=99ve come up with. =20
> Isn't this exactly what I describe in the first half of the writeup? This=
 still requires that the _actual_ object referred to is a subclass of T and=
 thus, to the best knowledge of the compiler, satisfied the Liskov substitu=
tion principle (I looked this up in Wikipedia as I didn=E2=80=99t know what=
 subsumption ment).
>=20
> =E2=80=A6


     Well, the entire point of concepts, run-time or compile-time, is that =
you can throw inheritance right out the window, right?  As long as the targ=
et object another, different object is working with exposes the interface i=
t expects, everything should work properly, as I understand it.  In additio=
n, when I referenced =E2=80=99subsumption,=E2=80=99 I really meant concept =
refinement:  it shouldn=E2=80=99t matter whether the target you=E2=80=99re =
handling via some interface uses it to fulfill either only the requirements=
 expected of itself by an object of a type designed to handle or work with =
it or a superset of them no matter what conceptual constraints the handle t=
ype expects of its target as long as the resulting behavior stays identical=
, correct? =20

> =E2=80=A6
>=20
>> Also, the part of your post where you started talking about maintaining =
object dispatch tables on top of the virtual function dispatch tables that =
already exist reminded me indirectly of some of the work that=E2=80=99s alr=
eady been done to describe and even implement open multimethods, but there=
=E2=80=99s a chance that this impression of mine could be somewhat misguide=
d.
> Yes, you are mistaken, this does not solve multimethod issues, it is rela=
ted to the case that the constructor src operand that the compiler thinks i=
s a U is really a subclass of U reimplementing any or all of its virtual me=
thods, thus requiring both a step to come from the "apparent" type T to U a=
nd a separate step from U to its subclass method (as the first step is fixe=
d at compile time for each call site while the latter can vary for each inv=
okation of the call site).
>=20
> =E2=80=A6


     What I meant is that the impression I originally got was that this mig=
ht involve something similar to the dispatch tables required for multimetho=
ds to work properly, but now I see that what you=E2=80=99ve been trying to =
describe bears more similarity to Objective-C method swizzling <http://nshi=
pster.com/method-swizzling/> than it does to the former, albeit not at bind=
/link time. =20

> =E2=80=A6
>=20
>>  The additional complexity you consider at the end probably doesn=E2=80=
=99t help, either, but, again, I=E2=80=99m not really the best individual t=
o go through all of this with somebody despite wanting to use it myself. =
=20
> As I point out it only allows using the proxy<T> containing a U in some c=
ontexts, i.e. when the T is the =E2=80=9Cthis" object.
>=20
> =E2=80=A6


     What about non-owning proxies, though?  And what if I wanted to have a=
 `proxy_of_one_type<proxy_of_another_type<U>>`? =20

> =E2=80=A6
>=20
>>=20
>> =E2=80=94=E2=80=89Bryce Glover
>> =E3=80=80=E2=80=89RandomDSdevel@gmail.com <mailto:RandomDSdevel@gmail.co=
m>
> --=20
> Bengt Gustafsson
> CEO, Beamways AB
> Westmansgatan 37
> 582 16 Link=C3=B6ping, Sweden
> +46 (705) 338259
> Skype: benke_g
> www.beamways.com <http://www.beamways.com/>
Still pondering,=20
     Bryce Glover
     RandomDSdevel@gmail.com

--=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/6AD8B3FD-9D97-433D-A4BC-DFD7E665159E%40gmail.com=
..

--Apple-Mail=_77AD6C72-BEE0-4652-8961-7EACCDAF02EF
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="UTF-8"

<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><div><blockquote t=
ype=3D"cite" class=3D""><div class=3D"">On May 15, 2017, at 2:22 PM, Bengt =
Gustafsson &lt;<a href=3D"mailto:bengt.gustafsson@beamways.com" class=3D"">=
bengt.gustafsson@beamways.com</a>&gt; wrote:</div><div class=3D""><div bgco=
lor=3D"#FFFFFF" text=3D"#000000" class=3D""><br class=3D"">
    <div class=3D"moz-cite-prefix">Den 2017-05-15 kl. 02:55, skrev Bryce
      Glover:<br class=3D"">
    </div>
    <blockquote cite=3D"mid:18DFAA3F-F4BB-4A9B-8B77-2F780F5BA4DE@gmail.com"=
 type=3D"cite" class=3D"">
      <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf=
-8" class=3D"">
      <blockquote type=3D"cite" class=3D"">(snipped=E2=80=A6)</blockquote>
      <br class=3D"">
      <div class=3D"">&nbsp; &nbsp; &nbsp;Implementing a way to hide the pa=
rts of itself
        that a derived class inherits from its parent base class behind
        a quasi-opaque, type-erasing =E2=80=98pointer to implementation=E2=
=80=99 from
        which it could then retrieve this information sounds like it
        could be interesting and could eventually end up being useful to
        <i class=3D"">somebody</i>, but I=E2=80=99m not entirely certain ho=
w well
        the introduction of such a concept contributes to the discussion
        undertaken in this thread so far. </div>
    </blockquote>
    Well, my intention was for this to become clear towards the end of
    the post, where the "proxy/interface" version of the indirect
    inheritance feature is discussed. I already had the indirect
    inheritance idea back when operator.() was discussed, as an
    alternative way to implement the handle classes it was aiming at.
    The main problem with operator.() was how to handle the ambiguity if
    both the handle class and its "T" had a method of the same name,
    which was solved in a tried and true way by viewing this as
    inheritance (i.e. the handle class method takes precedence and hides
    the T method unless a T:: is prefixed at the call site).</div></div></b=
lockquote><blockquote type=3D"cite" class=3D""><div class=3D""><div bgcolor=
=3D"#FFFFFF" text=3D"#000000" class=3D"">
    <br class=3D"">
    When the proxy/interface discussion started it became obvious that
    the requirements were similar: A template class is to implement the
    API of its template parameter T by some kind of forwarding, but in
    this case involving a translation table.<br class=3D""></div></div></bl=
ockquote><blockquote type=3D"cite" class=3D""><br class=3D""></blockquote><=
blockquote type=3D"cite" class=3D"">=E2=80=A6</blockquote><div><br class=3D=
""></div><div><div>&nbsp; &nbsp; &nbsp;Perhaps I=E2=80=99ve just gotten so =
tired of watching this discussion go around in circles even though I haven=
=E2=80=99t really contributed all that much to it that my eyes started to g=
laze over, thus explaining why I didn=E2=80=99t exactly notice how you mean=
t your thoughts to flow when I first skimmed your description of them. &nbs=
p;Rereading your original posting of this idea to this thread, as well as p=
rocessing it in light of the additional context you=E2=80=99ve just provide=
d here, has, I feel, let me start to catch on to where you=E2=80=99ve been =
trying to go with all of this. &nbsp;I remain somewhat confused, however, a=
s to why you can=E2=80=99t seem to figure out how to cleanly separate the a=
spect of this mechanism involving a =E2=80=98has a=E2=80=99 relationship of=
 type composition (that is, containment) from that related to the =E2=80=98=
is a=E2=80=99 relationship enforced by inheritance, but&nbsp;I=E2=80=99m st=
arting to appreciate how hard it might turn out to attempt disentangling th=
ese two orthogonal properties of a =E2=80=98forwards to=E2=80=99 relationsh=
ip when the forwarding object masquerades as its target object from how you=
=E2=80=99re explaining things. &nbsp;Still, I can=E2=80=99t help but feel t=
here could be an easier way to cut this Gordian knot despite not knowing ho=
w best to present my misgivings on this front. &nbsp;</div></div><div><br c=
lass=3D""></div><blockquote type=3D"cite" class=3D"">=E2=80=A6</blockquote>=
<blockquote type=3D"cite" class=3D""><div class=3D""><div bgcolor=3D"#FFFFF=
F" text=3D"#000000" class=3D"">
    <br class=3D"">
    My writeup is an attempt at showing how these two features can be
    stacked to achieve both goals.</div></div></blockquote><div><blockquote=
 type=3D"cite" class=3D""><br class=3D""></blockquote><blockquote type=3D"c=
ite" class=3D"">=E2=80=A6</blockquote></div><div><br class=3D""></div><div>=
&nbsp; &nbsp; &nbsp;No wonder I felt dizzy, then, what with the number of i=
ndirections involved and all! &nbsp;I couldn=E2=80=99t keep track of them, =
as they keep piling up! &nbsp;(Maybe I should just duck back out again and =
watch those of you with more expertise in matters like these hash things ou=
t, now that I think about it=E2=80=A6) &nbsp;In any case, t=E2=80=99d proba=
bly understand your proposal for how virtual concepts should work if you pr=
esented it <i class=3D"">separately</i>&nbsp;from this `operator .()`-relat=
ed =E2=80=98indirect inheritance idea, if asking you to do that is in any w=
ay a reasonable request. &nbsp;</div><div><br class=3D""></div><blockquote =
type=3D"cite" class=3D"">=E2=80=A6</blockquote><blockquote type=3D"cite" cl=
ass=3D""><div class=3D""><div bgcolor=3D"#FFFFFF" text=3D"#000000" class=3D=
"">
    <br class=3D"">
    Admittedly my approach is fairly different from the original
    proposer's who appointed the "magic features" to the new type of
    "thing" he called interface or proxy, while in my approach this
    declaration is just a regular struct/class declaration and the magic
    is in the indirect inheritance declaration.</div></div></blockquote><di=
v><blockquote type=3D"cite" class=3D""><br class=3D""></blockquote><blockqu=
ote type=3D"cite" class=3D"">=E2=80=A6</blockquote></div><div><br class=3D"=
"></div><div>&nbsp; &nbsp; &nbsp;It reduces the surface area of the new fun=
ctionality required to implement language-level type erasure, though, so th=
at=E2=80=99s good. &nbsp;</div><div><br class=3D""></div><blockquote type=
=3D"cite" class=3D"">=E2=80=A6</blockquote><blockquote type=3D"cite" class=
=3D""><div class=3D""><div bgcolor=3D"#FFFFFF" text=3D"#000000" class=3D"">
    <br class=3D"">
    <blockquote cite=3D"mid:18DFAA3F-F4BB-4A9B-8B77-2F780F5BA4DE@gmail.com"=
 type=3D"cite" class=3D"">
      <div class=3D"">&nbsp;<i class=3D"">Perhaps</i>&nbsp;one could implem=
ent a fully
        functional run-time concept wrapper implementing properly
        forwarding versions of the functionality expected of the type of
        objects the compile-time concept associated with this wrapper
        would require it to contain using this technique, but I feel
        both that a run-time concept facility should be easy to use by
        language users with abilities nearer to beginner level than this
        particular iteration of this construct and that said iteration
        doesn=E2=80=99t feel quite right to me when it comes to usability a=
nd
        understandability, but you should probably trust other peoples=E2=
=80=99
        reactions more than mine on this front, as I=E2=80=99m not the best
        person to give feedback on these kinds of matters. &nbsp;In any cas=
e,
        it strikes me that a version of this =E2=80=98indirect inheritance=
=E2=80=99 that
        one might consider more acceptably traditional would involve
        classes satisfying concepts related by subsumption, but that
        doesn=E2=80=99t really describe the model you=E2=80=99ve come up wi=
th.&nbsp; <br class=3D"">
      </div>
    </blockquote>
    Isn't this exactly what I describe in the first half of the writeup?
    This still requires that the _actual_ object referred to is a
    subclass of T and thus, to the best knowledge of the compiler,
    satisfied the Liskov substitution principle (I looked this up in
    Wikipedia as I didn=E2=80=99t know what subsumption ment).<br class=3D"=
"></div></div></blockquote><div><blockquote type=3D"cite" class=3D""><br cl=
ass=3D""></blockquote><blockquote type=3D"cite" class=3D"">=E2=80=A6</block=
quote></div><div><br class=3D""></div><div>&nbsp; &nbsp; &nbsp;Well, the en=
tire point of concepts, run-time or compile-time, is that you can throw inh=
eritance right out the window, right? &nbsp;As long as the target object an=
other, different object is working with exposes the interface it expects, e=
verything should work properly, as I understand it. &nbsp;In addition, when=
 I referenced =E2=80=99subsumption,=E2=80=99 I really meant concept <i clas=
s=3D"">refinement</i>: &nbsp;it shouldn=E2=80=99t matter whether the target=
 you=E2=80=99re handling via some interface uses it to fulfill either only =
the requirements expected of itself by an object of a type designed to hand=
le or work with it or a superset of them no matter what conceptual constrai=
nts the handle type expects of its target as long as the resulting behavior=
 stays identical, correct? &nbsp;</div><div><br class=3D""></div><div><bloc=
kquote type=3D"cite" class=3D"">=E2=80=A6</blockquote></div><blockquote typ=
e=3D"cite" class=3D""><br class=3D""></blockquote><blockquote type=3D"cite"=
 class=3D""><div class=3D""><div bgcolor=3D"#FFFFFF" text=3D"#000000" class=
=3D"">
    <blockquote cite=3D"mid:18DFAA3F-F4BB-4A9B-8B77-2F780F5BA4DE@gmail.com"=
 type=3D"cite" class=3D"">
      <div class=3D"">Also, the part of your post where you started
        talking about maintaining object dispatch tables on top of the
        virtual function dispatch tables that already exist reminded me
        indirectly of some of the work that=E2=80=99s already been done to
        describe and even implement open multimethods, but there=E2=80=99s =
a
        chance that <i class=3D"">this</i>&nbsp;impression of mine could be
        somewhat misguided. </div>
    </blockquote>
    Yes, you are mistaken, this does not solve multimethod issues, it is
    related to the case that the constructor src operand that the
    compiler thinks is a U is really a subclass of U reimplementing any
    or all of its virtual methods, thus requiring both a step to come
    from the "apparent" type T to U and a separate step from U to its
    subclass method (as the first step is fixed at compile time for each
    call site while the latter can vary for each invokation of the call
    site).<br class=3D""></div></div></blockquote><div><blockquote type=3D"=
cite" class=3D""><br class=3D""></blockquote><blockquote type=3D"cite" clas=
s=3D"">=E2=80=A6</blockquote></div><div><br class=3D""></div><div>&nbsp; &n=
bsp; &nbsp;What I meant is that the impression I originally got was that th=
is might involve something similar to the dispatch tables required for mult=
imethods to work properly, but now I see that what you=E2=80=99ve been tryi=
ng to describe bears more similarity to&nbsp;<a href=3D"http://nshipster.co=
m/method-swizzling/" class=3D"">Objective-C method swizzling</a>&nbsp;than =
it does to the former, albeit not at bind/link time. &nbsp;</div><div><br c=
lass=3D""></div><blockquote type=3D"cite" class=3D"">=E2=80=A6</blockquote>=
<blockquote type=3D"cite" class=3D""><div class=3D""><div bgcolor=3D"#FFFFF=
F" text=3D"#000000" class=3D"">
    <br class=3D"">
    <blockquote cite=3D"mid:18DFAA3F-F4BB-4A9B-8B77-2F780F5BA4DE@gmail.com"=
 type=3D"cite" class=3D"">
      <div class=3D"">&nbsp;The additional complexity you consider at the e=
nd
        probably doesn=E2=80=99t help, either, but, again, I=E2=80=99m not =
really the
        best individual to go through all of this with somebody despite
        wanting to use it myself.&nbsp; <br class=3D"">
      </div>
    </blockquote>
    As I point out it only allows using the proxy&lt;T&gt; containing a
    U in some contexts, i.e. when the T is the =E2=80=9Cthis" object.<br cl=
ass=3D""></div></div></blockquote><div><blockquote type=3D"cite" class=3D""=
><br class=3D""></blockquote><blockquote type=3D"cite" class=3D"">=E2=80=A6=
</blockquote></div><div><br class=3D""></div><div>&nbsp; &nbsp; &nbsp;What =
about non-owning proxies, though? &nbsp;And what if I wanted to have a `pro=
xy_of_one_type&lt;proxy_of_another_type&lt;U&gt;&gt;`? &nbsp;</div><div><br=
 class=3D""></div><div><blockquote type=3D"cite" class=3D"">=E2=80=A6</bloc=
kquote></div><blockquote type=3D"cite" class=3D""><br class=3D""></blockquo=
te><blockquote type=3D"cite" class=3D""><div class=3D""><div bgcolor=3D"#FF=
FFFF" text=3D"#000000" class=3D"">
    <blockquote cite=3D"mid:18DFAA3F-F4BB-4A9B-8B77-2F780F5BA4DE@gmail.com"=
 type=3D"cite" class=3D""><br class=3D"">
      <div class=3D"">
        <div style=3D"letter-spacing: normal; orphans: auto; text-align: st=
art; text-indent: 0px; text-transform: none; white-space: normal; widows: a=
uto; word-spacing: 0px; -webkit-text-stroke-width: 0px; word-wrap: break-wo=
rd; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=
=3D"">
          <div style=3D"letter-spacing: normal; orphans: auto; text-align: =
start; text-indent: 0px; text-transform: none; white-space: normal; widows:=
 auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; word-wrap: break-=
word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" cla=
ss=3D"">
            <div class=3D"">=E2=80=94=E2=80=89Bryce Glover</div>
            <div class=3D"">=E3=80=80=E2=80=89<a moz-do-not-send=3D"true" h=
ref=3D"mailto:RandomDSdevel@gmail.com" class=3D"">RandomDSdevel@gmail.com</=
a></div>
          </div>
        </div>
      </div>
    </blockquote>
    <br class=3D"">
    <pre class=3D"moz-signature" cols=3D"72">--=20
Bengt Gustafsson
CEO, Beamways AB
Westmansgatan 37
582 16 Link=C3=B6ping, Sweden
+46 (705) 338259
Skype: benke_g
<a class=3D"moz-txt-link-abbreviated" href=3D"http://www.beamways.com/">www=
..beamways.com</a></pre></div></div></blockquote></div><div class=3D"">
<div style=3D"color: rgb(0, 0, 0); letter-spacing: normal; orphans: auto; t=
ext-align: start; text-indent: 0px; text-transform: none; white-space: norm=
al; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; word-w=
rap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-=
space;" class=3D""><div style=3D"color: rgb(0, 0, 0); letter-spacing: norma=
l; orphans: auto; text-align: start; text-indent: 0px; text-transform: none=
; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke=
-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-=
break: after-white-space;" class=3D""><div style=3D"color: rgb(0, 0, 0); le=
tter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; t=
ext-transform: none; white-space: normal; widows: auto; word-spacing: 0px; =
-webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><div class=3D"">St=
ill pondering,&nbsp;</div><div class=3D"">&nbsp; &nbsp; &nbsp;Bryce Glover<=
/div><div class=3D"">&nbsp; &nbsp; &nbsp;<a href=3D"mailto:RandomDSdevel@gm=
ail.com" class=3D"">RandomDSdevel@gmail.com</a></div></div></div></div>
</div>
<br class=3D""></body></html>

<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/6AD8B3FD-9D97-433D-A4BC-DFD7E665159E%=
40gmail.com?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/6AD8B3FD-9D97-433D-A4BC-DFD7E665159E%=
40gmail.com</a>.<br />

--Apple-Mail=_77AD6C72-BEE0-4652-8961-7EACCDAF02EF--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Tue, 16 May 2017 14:46:14 -0700 (PDT)
Raw View
------=_Part_2546_413536240.1494971174821
Content-Type: multipart/alternative;
 boundary="----=_Part_2547_302901242.1494971174822"

------=_Part_2547_302901242.1494971174822
Content-Type: text/plain; charset="UTF-8"

I really do think that the feature I sketched in my last writing caters for
the needs you have identified. I do realize that it uses a quite different
method to achieve the goals, and the code examples I showed are just the
kind of "wrappers" that you (correctly) think will be necessary to get the
feature used.

I also hope that my approach corrects the shortcomings regarding lifetime
management that Nicol and others have pointed out with your approach, and
which I have not found any means to correct within the scope of that
approach. Furthermore I achieve this without having to invent a new type of
"struct declaration" and instead reuse the one we have.

To complement the solution for the complete "proxy" case my approach offers
a *light* version if you do have a common base class that the types you
want to type erase inherit from, this version having no runtime overhead
whatsoever compared to the underlying storage management (exemplified by
the shared_ptr or deep_ptr).

Maybe I did a pedagogical mistake in placing the *light* version at the top
of the writing, which is why I wrote about the plot twist to keep you guys
reading. To simplify here is a short form "gist" of the feature suggested:

- Indirect inheritance inherits functionality from an object whose
this-pointer is retrieved by calling a method on each use.

- Duck typed indirect inheritance augments this functionality by providing
a "compliant" type in the ctor's initializer list, which lets the compiler
create the required translation table.

For more info including rationale and examples see the previous post.

--
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/dafadc7f-a99b-4824-b975-124fd08a3b34%40isocpp.org.

------=_Part_2547_302901242.1494971174822
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>I really do think that the feature I sketched in my l=
ast writing caters for the needs you have identified. I do realize that it =
uses a quite different method to achieve the goals, and the code examples I=
 showed are just the kind of &quot;wrappers&quot; that you (correctly) thin=
k will be necessary to get the feature used.</div><div><br></div><div>I als=
o hope that my approach corrects the shortcomings regarding lifetime manage=
ment that Nicol and others have pointed out with your approach, and which I=
 have not found any means to correct within the scope of that approach. Fur=
thermore I achieve this without having to invent a new type of &quot;struct=
 declaration&quot; and instead reuse the one we have.</div><div><br></div><=
div>To complement the solution for the complete &quot;proxy&quot; case my a=
pproach offers a *light* version if you do have a common base class that th=
e types you want to type erase inherit from, this version having no runtime=
 overhead whatsoever compared to the underlying storage management (exempli=
fied by the shared_ptr or deep_ptr).=C2=A0</div><div><br></div><div>Maybe I=
 did a pedagogical mistake in placing the *light* version at the top of the=
 writing, which is why I wrote about the plot twist to keep you guys readin=
g. To simplify here is a short form &quot;gist&quot; of the feature suggest=
ed:</div><div><br></div><div>- Indirect inheritance inherits functionality =
from an object whose this-pointer is retrieved by calling a method on each =
use.</div><div><br></div><div>- Duck typed indirect inheritance augments th=
is functionality by providing a &quot;compliant&quot; type in the ctor&#39;=
s initializer list, which lets the compiler create the required translation=
 table.</div><div><br></div><div>For more info including rationale and exam=
ples see the previous post.</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/dafadc7f-a99b-4824-b975-124fd08a3b34%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/dafadc7f-a99b-4824-b975-124fd08a3b34=
%40isocpp.org</a>.<br />

------=_Part_2547_302901242.1494971174822--

------=_Part_2546_413536240.1494971174821--

.


Author: Mingxin Wang <wmx16835vv@163.com>
Date: Thu, 18 May 2017 07:26:29 -0700 (PDT)
Raw View
------=_Part_439_1138894211.1495117589831
Content-Type: multipart/alternative;
 boundary="----=_Part_440_1269595019.1495117589832"

------=_Part_440_1269595019.1495117589832
Content-Type: text/plain; charset="UTF-8"

According to your suggestions, I thought it over and carefully
reconstructed the wrapper that supports SSO optimization (sorry that I was
not familiar with this term before) as a prototype. Now the reconstructed
Wrapper<Runnable, 16> (16 is the maximum size of "small object" supported
for SSO optimization) *has the same size as std::function<void()>* (whose
size is 32, on the compiler I use, GCC 6.3.0) does.

In order to make the wrapper smaller, I deleted the proxy declaration in
the class template Wrapper, and *now the proxy is passed by value instead
of by reference* (see the implementation for more details).

After some performance tests, I found the newly implemented wrapper is more
efficient with copy constructor, template constructor (construct from an
arbitrary type that suitable for the specified proxy), destructor and
invoking (invoke the stored callable object with the proxy obtained by
Wrapper<Runnable>::get_proxy()), but less efficient with move constructor
than the implementation of std::function<void()> in GCC 6.3.0. Is there
something missing in the implementation? Or this is enough to prove that
the "proxies" is acceptable? After all, there is nothing we have that
supports this feature (except for std::function that only supports callable
objects) in the standard or TS.

The newly built implementation for the class template Wrapper is shown
below:

/* Holds a contiguous memory segment, sizeof(MemoryBlock<SIZE>) == SIZE */
template <std::size_t SIZE>
class MemoryBlock {
 public:
  MemoryBlock() = default;
  MemoryBlock(MemoryBlock&&) = default;
  MemoryBlock(const MemoryBlock&) = default;
  MemoryBlock& operator=(MemoryBlock&&) = default;
  MemoryBlock& operator=(const MemoryBlock&) = default;

  /* Access to the memory segment */
  void* get() { return data_; }

 private:
  char data_[SIZE];
};

// P: A proxy type
// SSO_SIZE: The maximum size for SSO optimization
template <class P, std::size_t SSO_SIZE = 16>
class Wrapper {
 public:
  /* Default constructor */
  Wrapper() { init(); }

  /* Initialize the wrapper with a concrete data */
  template <class T>
  Wrapper(T data) { init(std::move(data)); }

  /* Copy constructor */
  Wrapper(const Wrapper& rhs) {
    // There are two situations:
    //   1. rhs in invalid,
    //      *this shall also be invalid.
    //   2. rhs is valid, no matter whether SSO optimization is activated,
    //      *this shall be initialized with rhs.
    if (rhs.holder_ == nullptr) {
      init();
    } else {
      rhs.holder_->init(*this);
    }
  }

  /* Move constructor */
  Wrapper(Wrapper&& lhs) {
    // There are three situations:
    //   1. lhs in invalid,
    //      *this shall also be invalid.
    //   2. lhs is valid and SSO optimization is activated,
    //      *this shall be initialized with lhs.
    //   3. lhs in valid and SSO optimization is inactivated,
    //      The pointer of the holder can be simply moved from lhs to *this.
    if (lhs.holder_ == nullptr) {
      init();
    } else if (lhs.holder_ == lhs.sso_block_.get()) {
      lhs.holder_->init(*this);
    } else {
      holder_ = lhs.holder_;
      lhs.holder_ = nullptr;
    }
  }

  /* Destructor */
  ~Wrapper() {
    // There are two situations:
    //   1. SSO optimization is activated,
    //      The destructor of the holder shall be called without release
the memory.
    //   2. SSO optimization is inactivated,
    //      The pointer shall be deleted.
    //      If holder_ is a null pointer, this operation haves no
side-effect.
    if (holder_ == sso_block_.get()) {
      holder_->~AbstractHolder();
    } else {
      delete holder_;
    }
  }

  /* Access to the proxy */
  P get_proxy() { return holder_->get_proxy(); }

 private:
  /* The base class for lifetime management */
  class AbstractHolder {
   public:
    /* Virtual destructor */
    virtual ~AbstractHolder() {}

    /* Initialize another wrapper with *this */
    virtual void init(Wrapper&) = 0;

    /* Get a proxy */
    virtual P get_proxy() = 0;
  };

  template <class T>
  class ConcreteHolder : public AbstractHolder {
   public:
    /* Constructors */
    ConcreteHolder(T&& data) : data_(std::forward<T>(data)) {}
    ConcreteHolder(const T& data) : data_(data) {}
    ConcreteHolder(ConcreteHolder&&) = default;
    ConcreteHolder(const ConcreteHolder&) = default;

    /* Initialize the wrapper with the data (copy construct) */
    void init(Wrapper& wrapper) override { wrapper.init(data_); }

    P get_proxy() override { return P(data_); }

   private:
    T data_;
  };

  /* Initialize *this to be invalid */
  void init() { holder_ = nullptr; }

  /* Overload for small object */
  template <class T>
  void init(T&& data) requires (sizeof(T) <= SSO_SIZE) {
    // Let holder_ point to the reserved SSO block, and SSO optimization is
activated
    holder_ = reinterpret_cast<AbstractHolder*>(sso_block_.get());

    // Call the constructor of the ConcreteHolder without memory allocation
    new (reinterpret_cast<
        ConcreteHolder<std::remove_reference_t<T>>*>(sso_block_.get()))
        ConcreteHolder<std::remove_reference_t<T>>(std::forward<T>(data));
  }

  /* Overload for large object */
  template <class T>
  void init(T&& data) requires (sizeof(T) > SSO_SIZE) {
    // Let holder_ point to a "new" object, and SSO optimization is
inactivated
    holder_ = new
ConcreteHolder<std::remove_reference_t<T>>(std::forward<T>(data));
  }

  /* Associates with the lifetime management strategy */
  AbstractHolder* holder_;

  /* A reserved block for SSO optimization */
  MemoryBlock<sizeof(ConcreteHolder<MemoryBlock<SSO_SIZE>>)> sso_block_;
};

Mingxin Wang

--
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/6bd5959d-2ed7-411e-a489-c3f42362d0e9%40isocpp.org.

------=_Part_440_1269595019.1495117589832
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div><span style=3D"font-family: georgia, serif;">Accordin=
g to your suggestions, I thought it over and carefully reconstructed the wr=
apper that supports SSO optimization (sorry that I was not familiar with th=
is term before) as a prototype. Now the reconstructed Wrapper&lt;Runnable, =
16&gt; (16 is the maximum size of &quot;small object&quot; supported for SS=
O optimization) <b>has the same size as std::function&lt;void()&gt;</b> (wh=
ose size is 32, on the compiler I use, GCC 6.3.0) does.</span><br></div><di=
v><font face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia=
, serif">In order to make the wrapper smaller, I deleted the proxy declarat=
ion in the class template Wrapper, and <b>now the proxy is passed by value =
instead of by reference</b> (see the implementation for more details).</fon=
t></div><div><font face=3D"georgia, serif"><br></font></div><div><font face=
=3D"georgia, serif">After some performance tests, I found the newly impleme=
nted wrapper is more efficient with copy constructor, template constructor =
(construct from an arbitrary type that suitable for the specified proxy), d=
estructor and invoking (invoke the stored callable object with the proxy ob=
tained by Wrapper&lt;Runnable&gt;::get_proxy()), but less efficient with mo=
ve constructor than the implementation of std::function&lt;void()&gt; in GC=
C 6.3.0. Is there something missing in the implementation? Or this is enoug=
h to prove that the &quot;proxies&quot; is acceptable? After all, there is =
nothing we have that supports this feature (except for std::function that o=
nly supports callable objects) in the standard or TS.</font></div><div><fon=
t face=3D"georgia, serif"><br></font></div><div><font face=3D"georgia, seri=
f">The newly built implementation for the class template Wrapper is shown b=
elow:</font></div><div><font face=3D"georgia, serif"><br></font></div><div>=
<div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); w=
ord-wrap: break-word; background-color: rgb(250, 250, 250);"><code class=3D=
"prettyprint"><div class=3D"subprettyprint"><font color=3D"#660066"><div cl=
ass=3D"subprettyprint">/* Holds a contiguous memory segment, sizeof(MemoryB=
lock&lt;SIZE&gt;) =3D=3D SIZE */</div><div class=3D"subprettyprint">templat=
e &lt;std::size_t SIZE&gt;</div><div class=3D"subprettyprint">class MemoryB=
lock {</div><div class=3D"subprettyprint">=C2=A0public:</div><div class=3D"=
subprettyprint">=C2=A0 MemoryBlock() =3D default;</div><div class=3D"subpre=
ttyprint">=C2=A0 MemoryBlock(MemoryBlock&amp;&amp;) =3D default;</div><div =
class=3D"subprettyprint">=C2=A0 MemoryBlock(const MemoryBlock&amp;) =3D def=
ault;</div><div class=3D"subprettyprint">=C2=A0 MemoryBlock&amp; operator=
=3D(MemoryBlock&amp;&amp;) =3D default;</div><div class=3D"subprettyprint">=
=C2=A0 MemoryBlock&amp; operator=3D(const MemoryBlock&amp;) =3D default;</d=
iv><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=
=C2=A0 /* Access to the memory segment */</div><div class=3D"subprettyprint=
">=C2=A0 void* get() { return data_; }</div><div class=3D"subprettyprint"><=
br></div><div class=3D"subprettyprint">=C2=A0private:</div><div class=3D"su=
bprettyprint">=C2=A0 char data_[SIZE];</div><div class=3D"subprettyprint">}=
;</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint=
">// P: A proxy type</div><div class=3D"subprettyprint">// SSO_SIZE: The ma=
ximum size for SSO optimization</div><div class=3D"subprettyprint">template=
 &lt;class P, std::size_t SSO_SIZE =3D 16&gt;</div><div class=3D"subprettyp=
rint">class Wrapper {</div><div class=3D"subprettyprint">=C2=A0public:</div=
><div class=3D"subprettyprint">=C2=A0 /* Default constructor */</div><div c=
lass=3D"subprettyprint">=C2=A0 Wrapper() { init(); }</div><div class=3D"sub=
prettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Initialize t=
he wrapper with a concrete data */</div><div class=3D"subprettyprint">=C2=
=A0 template &lt;class T&gt;</div><div class=3D"subprettyprint">=C2=A0 Wrap=
per(T data) { init(std::move(data)); }</div><div class=3D"subprettyprint"><=
br></div><div class=3D"subprettyprint">=C2=A0 /* Copy constructor */</div><=
div class=3D"subprettyprint">=C2=A0 Wrapper(const Wrapper&amp; rhs) {</div>=
<div class=3D"subprettyprint">=C2=A0 =C2=A0 // There are two situations:</d=
iv><div class=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 1. rhs in invalid,=
</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 =C2=A0 =C2=A0*t=
his shall also be invalid.</div><div class=3D"subprettyprint">=C2=A0 =C2=A0=
 // =C2=A0 2. rhs is valid, no matter whether SSO optimization is activated=
,</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 =C2=A0 =C2=A0*=
this shall be initialized with rhs.</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 if (rhs.holder_ =3D=3D nullptr) {</div><div class=3D"subprettypr=
int">=C2=A0 =C2=A0 =C2=A0 init();</div><div class=3D"subprettyprint">=C2=A0=
 =C2=A0 } else {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 rh=
s.holder_-&gt;init(*this);</div><div class=3D"subprettyprint">=C2=A0 =C2=A0=
 }</div><div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subpretty=
print"><br></div><div class=3D"subprettyprint">=C2=A0 /* Move constructor *=
/</div><div class=3D"subprettyprint">=C2=A0 Wrapper(Wrapper&amp;&amp; lhs) =
{</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // There are three situa=
tions:</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 1. lhs in=
 invalid,</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 =C2=A0=
 =C2=A0*this shall also be invalid.</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 // =C2=A0 2. lhs is valid and SSO optimization is activated,</di=
v><div class=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 =C2=A0 =C2=A0*this =
shall be initialized with lhs.</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0 // =C2=A0 3. lhs in valid and SSO optimization is inactivated,</div>=
<div class=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 =C2=A0 =C2=A0The poin=
ter of the holder can be simply moved from lhs to *this.</div><div class=3D=
"subprettyprint">=C2=A0 =C2=A0 if (lhs.holder_ =3D=3D nullptr) {</div><div =
class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 init();</div><div class=3D"su=
bprettyprint">=C2=A0 =C2=A0 } else if (lhs.holder_ =3D=3D lhs.sso_block_.ge=
t()) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 lhs.holder_-=
&gt;init(*this);</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 } else {<=
/div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 holder_ =3D lhs.hol=
der_;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 lhs.holder_ =
=3D nullptr;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 }</div><div c=
lass=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br></d=
iv><div class=3D"subprettyprint">=C2=A0 /* Destructor */</div><div class=3D=
"subprettyprint">=C2=A0 ~Wrapper() {</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 // There are two situations:</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 // =C2=A0 1. SSO optimization is activated,</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 =C2=A0 =C2=A0The destructor of =
the holder shall be called without release the memory.</div><div class=3D"s=
ubprettyprint">=C2=A0 =C2=A0 // =C2=A0 2. SSO optimization is inactivated,<=
/div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // =C2=A0 =C2=A0 =C2=A0The=
 pointer shall be deleted.</div><div class=3D"subprettyprint">=C2=A0 =C2=A0=
 // =C2=A0 =C2=A0 =C2=A0If holder_ is a null pointer, this operation haves =
no side-effect.</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 if (holder=
_ =3D=3D sso_block_.get()) {</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 =C2=A0 holder_-&gt;~AbstractHolder();</div><div class=3D"subprettyprint=
">=C2=A0 =C2=A0 } else {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
=C2=A0 delete holder_;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 }</=
div><div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprin=
t"><br></div><div class=3D"subprettyprint">=C2=A0 /* Access to the proxy */=
</div><div class=3D"subprettyprint">=C2=A0 P get_proxy() { return holder_-&=
gt;get_proxy(); }</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">=C2=A0private:</div><div class=3D"subprettyprint">=C2=
=A0 /* The base class for lifetime management */</div><div class=3D"subpret=
typrint">=C2=A0 class AbstractHolder {</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0public:</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 /* Vi=
rtual destructor */</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 virtua=
l ~AbstractHolder() {}</div><div class=3D"subprettyprint"><br></div><div cl=
ass=3D"subprettyprint">=C2=A0 =C2=A0 /* Initialize another wrapper with *th=
is */</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 virtual void init(Wr=
apper&amp;) =3D 0;</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 /* Get a proxy */</div><div class=3D"subp=
rettyprint">=C2=A0 =C2=A0 virtual P get_proxy() =3D 0;</div><div class=3D"s=
ubprettyprint">=C2=A0 };</div><div class=3D"subprettyprint"><br></div><div =
class=3D"subprettyprint">=C2=A0 template &lt;class T&gt;</div><div class=3D=
"subprettyprint">=C2=A0 class ConcreteHolder : public AbstractHolder {</div=
><div class=3D"subprettyprint">=C2=A0 =C2=A0public:</div><div class=3D"subp=
rettyprint">=C2=A0 =C2=A0 /* Constructors */</div><div class=3D"subprettypr=
int">=C2=A0 =C2=A0 ConcreteHolder(T&amp;&amp; data) : data_(std::forward&lt=
;T&gt;(data)) {}</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 ConcreteH=
older(const T&amp; data) : data_(data) {}</div><div class=3D"subprettyprint=
">=C2=A0 =C2=A0 ConcreteHolder(ConcreteHolder&amp;&amp;) =3D default;</div>=
<div class=3D"subprettyprint">=C2=A0 =C2=A0 ConcreteHolder(const ConcreteHo=
lder&amp;) =3D default;</div><div class=3D"subprettyprint"><br></div><div c=
lass=3D"subprettyprint">=C2=A0 =C2=A0 /* Initialize the wrapper with the da=
ta (copy construct) */</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 voi=
d init(Wrapper&amp; wrapper) override { wrapper.init(data_); }</div><div cl=
ass=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 P get_proxy() override { return P(data_); }</div><div class=3D"subprett=
yprint"><br></div><div class=3D"subprettyprint">=C2=A0 =C2=A0private:</div>=
<div class=3D"subprettyprint">=C2=A0 =C2=A0 T data_;</div><div class=3D"sub=
prettyprint">=C2=A0 };</div><div class=3D"subprettyprint"><br></div><div cl=
ass=3D"subprettyprint">=C2=A0 /* Initialize *this to be invalid */</div><di=
v class=3D"subprettyprint">=C2=A0 void init() { holder_ =3D nullptr; }</div=
><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=
=A0 /* Overload for small object */</div><div class=3D"subprettyprint">=C2=
=A0 template &lt;class T&gt;</div><div class=3D"subprettyprint">=C2=A0 void=
 init(T&amp;&amp; data) requires (sizeof(T) &lt;=3D SSO_SIZE) {</div><div c=
lass=3D"subprettyprint">=C2=A0 =C2=A0 // Let holder_ point to the reserved =
SSO block, and SSO optimization is activated</div><div class=3D"subprettypr=
int">=C2=A0 =C2=A0 holder_ =3D reinterpret_cast&lt;AbstractHolder*&gt;(sso_=
block_.get());</div><div class=3D"subprettyprint"><br></div><div class=3D"s=
ubprettyprint">=C2=A0 =C2=A0 // Call the constructor of the ConcreteHolder =
without memory allocation</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
new (reinterpret_cast&lt;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 ConcreteHolder&lt;std::remove_reference_t&lt;T&gt;&gt;*&gt;(s=
so_block_.get()))</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 ConcreteHolder&lt;std::remove_reference_t&lt;T&gt;&gt;(std::forward&=
lt;T&gt;(data));</div><div class=3D"subprettyprint">=C2=A0 }</div><div clas=
s=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Over=
load for large object */</div><div class=3D"subprettyprint">=C2=A0 template=
 &lt;class T&gt;</div><div class=3D"subprettyprint">=C2=A0 void init(T&amp;=
&amp; data) requires (sizeof(T) &gt; SSO_SIZE) {</div><div class=3D"subpret=
typrint">=C2=A0 =C2=A0 // Let holder_ point to a &quot;new&quot; object, an=
d SSO optimization is inactivated</div><div class=3D"subprettyprint">=C2=A0=
 =C2=A0 holder_ =3D new ConcreteHolder&lt;std::remove_reference_t&lt;T&gt;&=
gt;(std::forward&lt;T&gt;(data));</div><div class=3D"subprettyprint">=C2=A0=
 }</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprin=
t">=C2=A0 /* Associates with the lifetime management strategy */</div><div =
class=3D"subprettyprint">=C2=A0 AbstractHolder* holder_;</div><div class=3D=
"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* A reserv=
ed block for SSO optimization */</div><div class=3D"subprettyprint">=C2=A0 =
MemoryBlock&lt;sizeof(ConcreteHolder&lt;MemoryBlock&lt;SSO_SIZE&gt;&gt;)&gt=
; sso_block_;</div><div class=3D"subprettyprint">};</div></font></div></cod=
e></div><div><font face=3D"georgia, serif"><br></font></div><font face=3D"g=
eorgia, serif">Mingxin Wang</font><br></div></div>

<p></p>

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

------=_Part_440_1269595019.1495117589832--

------=_Part_439_1138894211.1495117589831--

.