220 32773 <b61a514a-3a2b-4ce5-8bd3-984d547657a0@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: Mingxin Wang <wmx16835vv@163.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: The Proxies - A Language Feature Decoupling
 Implementations from Requirements of Polymorphism
Date: Wed, 14 Jun 2017 01:11:55 -0700 (PDT)
Lines: 506
Approved: news@gmane.org
Message-ID: <b61a514a-3a2b-4ce5-8bd3-984d547657a0@isocpp.org>
References: <8d79a013-fe0e-4fb6-8278-d438ae9b4c64@isocpp.org>
 <6416578b-a1b5-4124-8334-f735460038b5@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_4458_399239291.1497427915749"
X-Trace: blaine.gmane.org 1497427919 8110 195.159.176.226 (14 Jun 2017 08:11:59 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Wed, 14 Jun 2017 08:11:59 +0000 (UTC)
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBDNMBNHJWIGBBTG7QPFAKGQEPEH7AMY@isocpp.org Wed Jun 14 10:11:53 2017
Return-path: <std-proposals+bncBDNMBNHJWIGBBTG7QPFAKGQEPEH7AMY@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-pg0-f72.google.com ([74.125.83.72])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBDNMBNHJWIGBBTG7QPFAKGQEPEH7AMY@isocpp.org>)
	id 1dL3P6-0001ey-N9
	for gclcip-std-proposals@m.gmane.org; Wed, 14 Jun 2017 10:11:53 +0200
Original-Received: by mail-pg0-f72.google.com with SMTP id m19sf98916186pgd.14
        for <gclcip-std-proposals@m.gmane.org>; Wed, 14 Jun 2017 01:11:58 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=/GAmYiqiQg4z8+Mf/aUWJBaM6BoCPyyn/bVSuhfaRWw=;
        b=I+OGIE0efLSaYFL486hLfLYlKABrbsIJ+gGtxsWTHWA6/hiV0TFvB+zGYghQ11xQ3N
         17NAFzSPR6fl/fGiHEJX8Zz+xmqhRPz7YK+1W0vql9NGdgEgaAaAE27jFh/MpcbbgJoS
         VzkKtQ5PMlGD25XyToezsNCMjYM0mNKNdxZ2rglQbpYgDbzMLCVshd5q4p1koJGPwWta
         JaRKHEhkItrZPetGQrczh0jTgbuXKF5HVf6p8ixWZJrzJ5C6ZXOtoDf0QBbA/r3QBidU
         bprsIip3/k8CfO2/4Wmcer4qKup7rJ+H3iVITjtxFUj/8bmbKpp5mYS68UQAPg422d3W
         REdg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:date:from:to:message-id:in-reply-to:references
         :subject:mime-version:x-original-sender:reply-to:precedence
         :mailing-list:list-id:x-spam-checked-in-group:list-post:list-help
         :list-archive:list-subscribe:list-unsubscribe;
        bh=/GAmYiqiQg4z8+Mf/aUWJBaM6BoCPyyn/bVSuhfaRWw=;
        b=fBjtGsDWrvfMK+kiqukfMJVZgz5OZl8q2KSVFxU27J01LIe5FyeX4Z4c/G0v/xN9am
         dp76dPi1Pzd0KPIeasXvmqsraedJDZwgeeenRCRyQt7tVnnWi+YQZcoIcaUQdMBG/xz8
         okn178IONCob6yt86/OwRTKOloZI43f+2orbqBmriAnqrdn9T+j8UFCdnIoRbljQkevP
         nA8NqY06ytCEigL4UZT2EQCQsOYAx4BYX259BJIgJ1pHnZ4+0Kt+j4shbuhM7OzijmlB
         8wzxQbQo/ntMoP8BeadkvFnhkeOJoWMyZIY4JZNLOnMueV0x/3gL+3dCD/KvKQt48knm
         eGsA==
X-Gm-Message-State: AKS2vOyEqiIvVY0gKmClCN96F2L1wkhn0QF6WgcN1UnI1lyw6lVLTZso
	3cQotAs3mibWTb7C
X-Received: by 10.99.53.195 with SMTP id c186mr5031943pga.66.1497427917534;
        Wed, 14 Jun 2017 01:11:57 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.157.14.242 with SMTP id 105ls1057171otj.0.gmail; Wed, 14 Jun
 2017 01:11:56 -0700 (PDT)
X-Received: by 10.157.83.41 with SMTP id g41mr265219oth.13.1497427916360;
        Wed, 14 Jun 2017 01:11:56 -0700 (PDT)
In-Reply-To: <6416578b-a1b5-4124-8334-f735460038b5@isocpp.org>
X-Original-Sender: wmx16835vv@163.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:32773
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/32773>

------=_Part_4458_399239291.1497427915749
Content-Type: multipart/alternative; 
	boundary="----=_Part_4459_1857707340.1497427915750"

------=_Part_4459_1857707340.1497427915750
Content-Type: text/plain; charset="UTF-8"

On Tuesday, June 13, 2017 at 11:20:26 PM UTC+8, Nicol Bolas wrote:
>
> On Tuesday, June 13, 2017 at 9:49:43 AM UTC-4, Mingxin Wang wrote:
>>
>> *Technical Specifications*
>>
>> *Wrapper requirements*
>>
>> A type W meets the Wrapper requirements if the following expressions are 
>> well-formed and have the specific semantics (w denotes a value of type W).
>>
>> w.get()
>> Requires: w is initialized with an object.
>> Effects: acquires the pointer of the wrapped object if there is one.
>> Return type: void*.
>> Returns: a pointer of the wrapped object.
>>
>>
> This seems decidedly thin on details.
>
> As I understand your design, the "wrapper" provides both the storage for 
> the object/pointer as well as determining the semantics relative to that 
> object/pointer. This is not entirely clear from your technical 
> specifications, but everything else I'm going to say is based on this 
> assumption.
>
> A "Wrapper" is only required to support semantics for addressing (at 
minimum).
 

> First, "wrapper" is a *terrible* name for this concept. It isn't 
> "wrapping" anything; it's providing storage and specifying the semantics of 
> the proxy (which also isn't a particularly good name). That isn't 
> "wrapping". It's simply providing the semantics of the type. So "Semantics" 
> seems a much more descriptive name.
>
> I think "Semantics" is not as good as "Wrapper". As this is a relatively 
subjective issue, maybe we need more feedback and discuss about it later.
 

> Second, the `get` interface is entirely insufficient to fully define this 
> concept. The "wrapper" needs to be able to be initialized from any object 
> that matches `I`, so that has to be part of its interface. Your example 
> code shows this, but these "Wrapper requirements" don't mention it. 
> Furthermore:
>
> There is no particular requirements on "what type can be used to construct 
a wrapper". Actually, a type that meets the Wrapper requirements may carry 
such constraints on its constructors.
  

> Third, it's not clear who is actually responsible for the *type erasure* 
> part of this. The type `T` provided to a "proxy" seems to be erased by the 
> code generated data. But since the "wrapper" holds the storage for said 
> `T`, it must also have enough information to *destroy* that object. After 
> all, the "wrapper" may copy/move from the given `T` into new storage for 
> that `T`. Which means that the "wrapper" implementation has to know what 
> that `T` was when it goes to destroy it.
>
> A Wrapper may be responsible to destroy an object just as std::any does, 
and a Proxy is responsible for ACCESSING the object without RTTI.
 

> This means that any "wrapper" that actually owns a `T` must *itself* 
> perform type-erasure, for the purpose of destroying the `T`. We discussed 
> this in your last thread. Double-type-erasure is less efficient than 
> single-type-erasure, thus violating one of your design goals.
>
> Not exactly. Double-type-erasure only requires a little more memory 
(one-pointer size) and is more compatible. That is why we usually use 
"combination instead of inheritance" in architecture designing. Besides, I 
have ran a performance test for DeepWrapper<Callable<void()>, 16u> and 
std::function<void()> which have the same SOO size on my compiler (Windows 
7 x64, gcc version 6.3.0 x86_64-posix-seh-rev2, Built by MinGW-W64 project, 
Command: g++.exe -march=corei7-avx -O2 -m64 -fconcepts -std=c++17), and the 
result turns out to be positive that DeepWrapper<Callable<void()>, 16u> is 
more efficient than the implementation of std::function<void()> most of the 
time because there is an extra addressing operation for the virtual table 
for std::function<void()>, as is shown below (x: the size of the object for 
type erasure; y: the time elapsed):

<https://lh3.googleusercontent.com/-_gjJzdIwPp4/WUDlTwYKtUI/AAAAAAAAAE8/Vl08JuotE1cfLt6bRyWB7HQtNeWmkqKBgCLcBGAs/s1600/Untitled.png>

<https://lh3.googleusercontent.com/-mDVlwZYpOgM/WUDlbYCiEBI/AAAAAAAAAFA/GNdldWXiF6MjcH54bljg9OaUSJFMQDiwACLcBGAs/s1600/Untitled.png>

<https://lh3.googleusercontent.com/-a7Z1kFHkaEA/WUDliSb7vOI/AAAAAAAAAFE/YvcQfqvOGL0AZw4i_aLW7wLZBoHbhOVFwCLcBGAs/s1600/Untitled.png>
 

> Now, you might be able to work around this problem. You could design it so 
> that the "wrapper" explicitly advertises in its interface that it is an 
> "owning" wrapper, such that it needs to be provided with the un-erased `T` 
> when the "proxy" is being destroyed. But that's a much more complex 
> interface than you have outlined here.
>

This is not always necessary, especially when W is a trivial type.
 

> *Class template proxy*
>>
>> Expression "proxy<I, W>" is a well-formed type if I is a pure virtual 
>> class (without a virtual destructor) and W is a type meets the Wrapper 
>> requirements defined above.
>>
>> "proxy<I, W>" is MoveConstructible if W is MoveConstructible, while 
>> "proxy<I, W>" is CopyConstructible if W is CopyConstructible.
>>
>> Providing p is a value of "proxy<I, W>" and i is a pointer of I, 
>> "p.f(args...)" shall be a valid expression if "(*i).f(args...)" is a valid 
>> expression, where f is any valid function name (including operator 
>> overloads) and "args..." is any valid combination of values of any type.
>>
>
> As previously mentioned, the "proxy" ought to provide `any_cast`-like 
> functionality. That is, the ability to extract an object/reference to the 
> exact `T` which was provided. Since the "proxy" type's semantics are part 
> of its type declaration (defined by `W`), it would be easy to specialize 
> the interface for reference proxies vs. value proxies.
>
> Alternatively, you could use the `std::function::target` interface for a 
> lighter-weight version. But the overall point is the same: a type-erased 
> type ought to be able to extract what it was given.
>
> Yes, This is a question worth considering. Luckily, this does not require 
reconstructing, we can simply "add" the feature to this solution. Maybe we 
can have something like "std::any_cast":

template<class ValueType, class I, class W>
ValueType proxy_cast(const proxy<I, W>& operand);

template<class ValueType, class I, class W>
ValueType proxy_cast(proxy<I, W>& operand);

template<class ValueType, class I, class W>
ValueType proxy_cast(proxy<I, W>&& operand);

template<class ValueType, class I, class W>
const ValueType* proxy_cast(const proxy<I, W>* operand) noexcept;

template<class ValueType, class I, class W>
ValueType* proxy_cast(proxy<I, W>* operand) noexcept;

Implementations may use dynamic_cast for RTTI. To clarify this issue, we 
may as well assume there is an invisible "helper" member function in the 
class template proxy for the function templates defined above, as is shown 
below:

template <class I, class W> requires Wrapper<W>()
class proxy<I, W> {
 public:
  // ...
  template <class T>
  T* __cast() {
    Abstraction* ptr = 
dynamic_cast<Implementation<T>*>(reinterpret_cast<Abstraction*>(data_.get()));
    return ptr == nullptr ? nullptr : 
reinterpret_cast<T*>(ptr->wrapper_.get());
  }
  // ...
  
 private:
  class Abstraction : public I {
   public:
    /* ... */
    W wrapper_;
  };
  
  class Uninitialized : public Abstraction { /* ... */ };
  
  template <class T>
  class Implementation : public Abstraction { /* ... */ };
  
  MemoryBlock<sizeof(Uninitialized)> data_;
};

*Prototypes for Wrappers*
>>
>> Class "SharedWrapper" (with shared semantics), class template 
>> "DeepWrapper" (with value semantics and SOO feature) and class 
>> "DefferedWrapper" (with reference semantics) are designed to meet the 
>> Wrapper requirements. Possible implementation is included in the 
>> attachments.
>>
>
> "DeepWrapper" is the wrong name. It provides "value semantics". Calling it 
> "deep" suggests "deep copying", which is *not* what this provides. It 
> should simply be "ValueWrapper". And there should also be a 
> "MoveValueWrapper", for use in cases where you want to allow users to 
> provide move-only types.
>  
>
"DefferedWrapper" is similarly misnamed (though also misspelled). It 
> provides "reference semantics", so it is a "ReferenceWrapper". Admittedly, 
> we already have a type with that name, but that's another reason not to 
> call them "wrappers" at all.
>
> I am sorry about the misspelling. It should be "DeferredWrapper" rather 
than "DefferedWrapper". Still, I suggest we need more feedback and discuss 
the naming issue later.
 

> Also, it's not clear what "SharedWrapper" means. Does it copy/move into 
> memory owned by the proxy, ala `make_shared`? Can you pass it a 
> `shared_ptr<T>` instead of a `T`, so that you can share ownership of the 
> object with the proxy? If not, why not? If you're going to allow shared 
> ownership of the value, then it is just as reasonable to allow shared 
> ownership of the value with objects that *aren't* the proxy.
>
> Like class template std::shared_ptr, "SharedWrapper" is also based on 
reference-counting.The differences between the two are:

   - std::shared_ptr is based on pointer semantics, whose general layout 
   requires two unrelated memory block (that is why we prefer to use 
   "std::make_shared" to avoid "twice memory allocation", and why some people 
   dislike std::shared_ptr), while SharedWrapper only requires one memory 
   block maintaining both the reference-count and the value of the concrete 
   object (rather than a pointer of the concrete object). Thus there is no 
   conversion between std::shared_ptr and SharedWrapper as they have different 
   structures.
   - std::shared_ptr is type-specific, while SharedWrapper is type-erased.

See the implementation (shared_wrapper.hpp) included in src.zip for more 
details.

This is one of the problems of going to a generic mechanism for handling 
> semantics: the rabbit hole of possibilities is infinite.
>
> That being said, since the "wrapper" is part of the proxy's template 
> declaration, it is possible to have the "wrapper" actually influence the 
> proxy's interface. So the "wrapper" could affect the definition of the 
> proxy's template constructor from `T`, as well as the template function 
> which extracts a pointer/reference to the proxied type. A `SharedWrapper` 
> could therefore allow you to pass a `shared_ptr<T>`, as well as allow you 
> to extract a `shared_ptr<T>`.
>

-- 
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b61a514a-3a2b-4ce5-8bd3-984d547657a0%40isocpp.org.

------=_Part_4459_1857707340.1497427915750
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Tuesday, June 13, 2017 at 11:20:26 PM UTC+8, Nicol Bola=
s wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On Tu=
esday, June 13, 2017 at 9:49:43 AM UTC-4, Mingxin Wang wrote:<blockquote cl=
ass=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><font size=3D"6"=
><b>Technical Specifications</b></font></div><div><br></div><div><font size=
=3D"4"><b>Wrapper requirements</b></font></div><div><br></div><div>A type W=
 meets the Wrapper requirements if the following expressions are well-forme=
d and have the specific semantics (w denotes a value of type W).</div><div>=
<br></div><div>w.get()</div><div><span style=3D"white-space:pre">	</span>Re=
quires: w is initialized with an object.</div><div><span style=3D"white-spa=
ce:pre">	</span>Effects: acquires the pointer of the wrapped object if ther=
e is one.</div><div><span style=3D"white-space:pre">	</span>Return type: vo=
id*.</div><div><span style=3D"white-space:pre">	</span>Returns: a pointer o=
f the wrapped object.</div><div><br></div></div></blockquote><div><br>This =
seems decidedly thin on details.<br><br>As I understand your design, the &q=
uot;wrapper&quot; provides both the storage for the object/pointer as well =
as determining the semantics relative to that object/pointer. This is not e=
ntirely clear from your technical specifications, but everything else I&#39=
;m going to say is based on this assumption.<br><br></div></div></blockquot=
e><div>A &quot;Wrapper&quot; is only required to support semantics for addr=
essing (at minimum).</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>First, &quot;wrapper&quot; is a <i>terri=
ble</i> name for this concept. It isn&#39;t &quot;wrapping&quot; anything; =
it&#39;s providing storage and specifying the semantics of the proxy (which=
 also isn&#39;t a particularly good name). That isn&#39;t &quot;wrapping&qu=
ot;. It&#39;s simply providing the semantics of the type. So &quot;Semantic=
s&quot; seems a much more descriptive name.<br><br></div></div></blockquote=
><div>I think &quot;Semantics&quot; is not as good as &quot;Wrapper&quot;. =
As this is a relatively subjective issue, maybe we need more feedback and d=
iscuss about it later.</div><div>=C2=A0</div><blockquote class=3D"gmail_quo=
te" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddi=
ng-left: 1ex;"><div dir=3D"ltr"><div>Second, the `get` interface is entirel=
y insufficient to fully define this concept. The &quot;wrapper&quot; needs =
to be able to be initialized from any object that matches `I`, so that has =
to be part of its interface. Your example code shows this, but these &quot;=
Wrapper requirements&quot; don&#39;t mention it. Furthermore:<br><br></div>=
</div></blockquote><div>There is no particular requirements on &quot;what t=
ype can be used to construct a wrapper&quot;. Actually, a type that meets t=
he Wrapper requirements may carry such constraints on its constructors.</di=
v><div>=C2=A0=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>Third, it&#39;s not clear who is actually responsible for =
the <i>type erasure</i> part of this. The type `T` provided to a &quot;prox=
y&quot; seems to be erased by the code generated data. But since the &quot;=
wrapper&quot; holds the storage for said `T`, it must also have enough info=
rmation to <i>destroy</i> that object. After all, the &quot;wrapper&quot; m=
ay copy/move from the given `T` into new storage for that `T`. Which means =
that the &quot;wrapper&quot; implementation has to know what that `T` was w=
hen it goes to destroy it.<br><br></div></div></blockquote><div>A Wrapper m=
ay be responsible to destroy an object just as std::any does, and a Proxy i=
s responsible for ACCESSING the object without RTTI.</div><div>=C2=A0</div>=
<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"><div>This mea=
ns that any &quot;wrapper&quot; that actually owns a `T` must <i>itself</i>=
 perform type-erasure, for the purpose of destroying the `T`. We discussed =
this in your last thread. Double-type-erasure is less efficient than single=
-type-erasure, thus violating one of your design goals.<br><br></div></div>=
</blockquote><div>Not exactly. Double-type-erasure only requires a little m=
ore memory (one-pointer size) and is more compatible. That is why we usuall=
y use &quot;combination instead of inheritance&quot; in architecture design=
ing. Besides, I have ran a performance test for DeepWrapper&lt;Callable&lt;=
void()&gt;, 16u&gt; and std::function&lt;void()&gt; which have the same SOO=
 size on my compiler (Windows 7 x64, gcc version 6.3.0 x86_64-posix-seh-rev=
2, Built by MinGW-W64 project, Command: g++.exe -march=3Dcorei7-avx -O2 -m6=
4 -fconcepts -std=3Dc++17), and the result turns out to be positive that De=
epWrapper&lt;Callable&lt;void()&gt;, 16u&gt; is more efficient than the imp=
lementation of std::function&lt;void()&gt; most of the time because there i=
s an extra addressing operation for the virtual table for std::function&lt;=
void()&gt;, as is shown below (x: the size of the object for type erasure; =
y: the time elapsed):</div><div><br></div><p class=3D"separator" style=3D"t=
ext-align: center; clear: both;"><a imageanchor=3D"1" href=3D"https://lh3.g=
oogleusercontent.com/-_gjJzdIwPp4/WUDlTwYKtUI/AAAAAAAAAE8/Vl08JuotE1cfLt6bR=
yWB7HQtNeWmkqKBgCLcBGAs/s1600/Untitled.png" style=3D"margin-left: 1em; marg=
in-right: 1em;"><img src=3D"https://lh3.googleusercontent.com/-_gjJzdIwPp4/=
WUDlTwYKtUI/AAAAAAAAAE8/Vl08JuotE1cfLt6bRyWB7HQtNeWmkqKBgCLcBGAs/s320/Untit=
led.png" border=3D"0" style=3D"" width=3D"320" height=3D"212"></a></p><div>=
<br></div><p class=3D"separator" style=3D"text-align: center; clear: both;"=
><a imageanchor=3D"1" href=3D"https://lh3.googleusercontent.com/-mDVlwZYpOg=
M/WUDlbYCiEBI/AAAAAAAAAFA/GNdldWXiF6MjcH54bljg9OaUSJFMQDiwACLcBGAs/s1600/Un=
titled.png" style=3D"margin-left: 1em; margin-right: 1em;"><img src=3D"http=
s://lh3.googleusercontent.com/-mDVlwZYpOgM/WUDlbYCiEBI/AAAAAAAAAFA/GNdldWXi=
F6MjcH54bljg9OaUSJFMQDiwACLcBGAs/s320/Untitled.png" border=3D"0" style=3D""=
 width=3D"320" height=3D"212"></a></p><div><br></div><p class=3D"separator"=
 style=3D"text-align: center; clear: both;"><a imageanchor=3D"1" href=3D"ht=
tps://lh3.googleusercontent.com/-a7Z1kFHkaEA/WUDliSb7vOI/AAAAAAAAAFE/YvcQfq=
vOGL0AZw4i_aLW7wLZBoHbhOVFwCLcBGAs/s1600/Untitled.png" style=3D"margin-left=
: 1em; margin-right: 1em;"><img src=3D"https://lh3.googleusercontent.com/-a=
7Z1kFHkaEA/WUDliSb7vOI/AAAAAAAAAFE/YvcQfqvOGL0AZw4i_aLW7wLZBoHbhOVFwCLcBGAs=
/s320/Untitled.png" border=3D"0" style=3D"" width=3D"320" height=3D"213"></=
a></p><div>=C2=A0<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>Now, you might be able to work around this problem. You =
could design it so that the &quot;wrapper&quot; explicitly advertises in it=
s interface that it is an &quot;owning&quot; wrapper, such that it needs to=
 be provided with the un-erased `T` when the &quot;proxy&quot; is being des=
troyed. But that&#39;s a much more complex interface than you have outlined=
 here.</div></div></blockquote><div><br></div><div>This is not always neces=
sary, especially when W is a trivial type.</div><div>=C2=A0</div><blockquot=
e class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: =
1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></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><div><font size=3D"=
4"><b>Class template proxy</b></font></div><div><br></div><div>Expression &=
quot;proxy&lt;I, W&gt;&quot; is a well-formed type if I is a pure virtual c=
lass (without a virtual destructor) and W is a type meets the Wrapper requi=
rements defined above.</div><div><br></div><div>&quot;proxy&lt;I, W&gt;&quo=
t; is MoveConstructible if W is MoveConstructible, while &quot;proxy&lt;I, =
W&gt;&quot; is CopyConstructible if W is CopyConstructible.</div><div><br><=
/div><div>Providing p is a value of &quot;proxy&lt;I, W&gt;&quot; and i is =
a pointer of I, &quot;p.f(args...)&quot; shall be a valid expression if &qu=
ot;(*i).f(args...)&quot; is a valid expression, where f is any valid functi=
on name (including operator overloads) and &quot;args...&quot; is any valid=
 combination of values of any type.</div></div></blockquote><div><br>As pre=
viously mentioned, the &quot;proxy&quot; ought to provide `any_cast`-like f=
unctionality. That is, the ability to extract an object/reference to the ex=
act `T` which was provided. Since the &quot;proxy&quot; type&#39;s semantic=
s are part of its type declaration (defined by `W`), it would be easy to sp=
ecialize the interface for reference proxies vs. value proxies.<br><br>Alte=
rnatively, you could use the `std::function::target` interface for a lighte=
r-weight version. But the overall point is the same: a type-erased type oug=
ht to be able to extract what it was given.<br><br></div></div></blockquote=
><div>Yes, This is a question worth considering. Luckily, this does not req=
uire reconstructing, we can simply &quot;add&quot; the feature to this solu=
tion. Maybe we can have something like &quot;std::any_cast&quot;:</div><div=
><br></div><div><div class=3D"prettyprint" style=3D"border: 1px solid rgb(1=
87, 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 ValueType, class I=
, class W&gt;</div><div class=3D"subprettyprint">ValueType proxy_cast(const=
 proxy&lt;I, W&gt;&amp; operand);</div><div class=3D"subprettyprint"><br></=
div><div class=3D"subprettyprint">template&lt;class ValueType, class I, cla=
ss W&gt;</div><div class=3D"subprettyprint">ValueType proxy_cast(proxy&lt;I=
, W&gt;&amp; operand);</div><div class=3D"subprettyprint"><br></div><div cl=
ass=3D"subprettyprint">template&lt;class ValueType, class I, class W&gt;</d=
iv><div class=3D"subprettyprint">ValueType proxy_cast(proxy&lt;I, W&gt;&amp=
;&amp; operand);</div><div class=3D"subprettyprint"><br></div><div class=3D=
"subprettyprint">template&lt;class ValueType, class I, class W&gt;</div><di=
v class=3D"subprettyprint">const ValueType* proxy_cast(const proxy&lt;I, W&=
gt;* operand) noexcept;</div><div class=3D"subprettyprint"><br></div><div c=
lass=3D"subprettyprint">template&lt;class ValueType, class I, class W&gt;</=
div><div class=3D"subprettyprint">ValueType* proxy_cast(proxy&lt;I, W&gt;* =
operand) noexcept;</div></font></div></code></div><br>Implementations may u=
se dynamic_cast for RTTI. To clarify this issue, we may as well assume ther=
e is an invisible &quot;helper&quot; member function in the class template =
proxy for the function templates defined above, as is shown below:</div><di=
v><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 I, class W&gt; requires Wrapper&lt;W&gt;=
()</div><div class=3D"subprettyprint">class proxy&lt;I, W&gt; {</div><div c=
lass=3D"subprettyprint">=C2=A0public:</div><div class=3D"subprettyprint">=
=C2=A0 // ...</div><div class=3D"subprettyprint">=C2=A0 template &lt;class =
T&gt;</div><div class=3D"subprettyprint">=C2=A0 T* __cast() {</div><div cla=
ss=3D"subprettyprint">=C2=A0 =C2=A0 Abstraction* ptr =3D dynamic_cast&lt;Im=
plementation&lt;T&gt;*&gt;(reinterpret_cast&lt;Abstraction*&gt;(data_.get()=
));</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return ptr =3D=3D null=
ptr ? nullptr : reinterpret_cast&lt;T*&gt;(ptr-&gt;wrapper_.get());</div><d=
iv class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint">=C2=
=A0 // ...</div><div class=3D"subprettyprint">=C2=A0=C2=A0</div><div class=
=3D"subprettyprint">=C2=A0private:</div><div class=3D"subprettyprint">=C2=
=A0 class Abstraction : public I {</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0public:</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 /* ... *=
/</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 W wrapper_;</div><div cl=
ass=3D"subprettyprint">=C2=A0 };</div><div class=3D"subprettyprint">=C2=A0=
=C2=A0</div><div class=3D"subprettyprint">=C2=A0 class Uninitialized : publ=
ic Abstraction { /* ... */ };</div><div class=3D"subprettyprint">=C2=A0=C2=
=A0</div><div class=3D"subprettyprint">=C2=A0 template &lt;class T&gt;</div=
><div class=3D"subprettyprint">=C2=A0 class Implementation : public Abstrac=
tion { /* ... */ };</div><div class=3D"subprettyprint">=C2=A0=C2=A0</div><d=
iv class=3D"subprettyprint">=C2=A0 MemoryBlock&lt;sizeof(Uninitialized)&gt;=
 data_;</div><div class=3D"subprettyprint">};</div></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></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-le=
ft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div=
></div><div><b><font size=3D"4">Prototypes for Wrappers</font></b></div><di=
v><br></div><div>Class &quot;SharedWrapper&quot; (with shared semantics), c=
lass template &quot;DeepWrapper&quot; (with value semantics and SOO feature=
) and class &quot;DefferedWrapper&quot; (with reference semantics) are desi=
gned to meet the Wrapper requirements. Possible implementation is included =
in the attachments.</div></div></blockquote><div><br>&quot;DeepWrapper&quot=
; is the wrong name. It provides &quot;value semantics&quot;. Calling it &q=
uot;deep&quot; suggests &quot;deep copying&quot;, which is <i>not</i> what =
this provides. It should simply be &quot;ValueWrapper&quot;. And there shou=
ld also be a &quot;MoveValueWrapper&quot;, for use in cases where you want =
to allow users to provide move-only types.<br>=C2=A0<br></div></div></block=
quote><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"><div>&q=
uot;DefferedWrapper&quot; is similarly misnamed (though also misspelled). I=
t provides &quot;reference semantics&quot;, so it is a &quot;ReferenceWrapp=
er&quot;. Admittedly, we already have a type with that name, but that&#39;s=
 another reason not to call them &quot;wrappers&quot; at all.<br><br></div>=
</div></blockquote><div>I am sorry about the misspelling. It should be &quo=
t;DeferredWrapper&quot; rather than &quot;DefferedWrapper&quot;. Still, I s=
uggest we need more feedback and discuss the naming issue later.</div><div>=
=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><=
div>Also, it&#39;s not clear what &quot;SharedWrapper&quot; means. Does it =
copy/move into memory owned by the proxy, ala `make_shared`? Can you pass i=
t a `shared_ptr&lt;T&gt;` instead of a `T`, so that you can share ownership=
 of the object with the proxy? If not, why not? If you&#39;re going to allo=
w shared ownership of the value, then it is just as reasonable to allow sha=
red ownership of the value with objects that <i>aren&#39;t</i> the proxy.<b=
r><br></div></div></blockquote><div>Like class template std::shared_ptr, &q=
uot;SharedWrapper&quot; is also based on reference-counting.The differences=
 between the two are:</div><div><ul><li><span style=3D"line-height: normal;=
">std::shared_ptr is based on pointer semantics, whose general layout requi=
res two unrelated memory block (that is why we prefer to use &quot;std::mak=
e_shared&quot; to avoid &quot;twice memory allocation&quot;, and why some p=
eople dislike std::shared_ptr), while SharedWrapper only requires one memor=
y block maintaining both the reference-count and the value of the concrete =
object (rather than a pointer of the concrete object). Thus there is no con=
version between std::shared_ptr and SharedWrapper as they have different st=
ructures.</span></li><li><span style=3D"line-height: normal;">std::shared_p=
tr is type-specific, while SharedWrapper is type-erased.</span></li></ul>Se=
e the implementation (shared_wrapper.hpp) included in src.zip for more deta=
ils.</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> This is one of the problems of going to a generic mechani=
sm for=20
handling semantics: the rabbit hole of possibilities is infinite.<br><br>Th=
at being said, since the &quot;wrapper&quot; is part of the proxy&#39;s tem=
plate declaration, it is possible to have the &quot;wrapper&quot; actually =
influence the proxy&#39;s interface. So the &quot;wrapper&quot; could affec=
t the definition of the proxy&#39;s template constructor from `T`, as well =
as the template function which extracts a pointer/reference to the proxied =
type. A `SharedWrapper` could therefore allow you to pass a `shared_ptr&lt;=
T&gt;`, as well as allow you to extract a `shared_ptr&lt;T&gt;`.<br></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/b61a514a-3a2b-4ce5-8bd3-984d547657a0%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/b61a514a-3a2b-4ce5-8bd3-984d547657a0=
%40isocpp.org</a>.<br />

------=_Part_4459_1857707340.1497427915750--

------=_Part_4458_399239291.1497427915749--

.
