220 32752 <8d79a013-fe0e-4fb6-8278-d438ae9b4c64@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: The Proxies - A Language Feature Decoupling
 Implementations from Requirements of Polymorphism
Date: Tue, 13 Jun 2017 06:49:42 -0700 (PDT)
Lines: 747
Approved: news@gmane.org
Message-ID: <8d79a013-fe0e-4fb6-8278-d438ae9b4c64@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_1692_922395550.1497361782856"
X-Trace: blaine.gmane.org 1497361788 12524 195.159.176.226 (13 Jun 2017 13:49:48 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Tue, 13 Jun 2017 13:49:48 +0000 (UTC)
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBDNMBNHJWIGBB56277EQKGQEQYUHEGA@isocpp.org Tue Jun 13 15:49:41 2017
Return-path: <std-proposals+bncBDNMBNHJWIGBB56277EQKGQEQYUHEGA@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-qt0-f200.google.com ([209.85.216.200])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBDNMBNHJWIGBB56277EQKGQEQYUHEGA@isocpp.org>)
	id 1dKmCT-0002oS-7B
	for gclcip-std-proposals@m.gmane.org; Tue, 13 Jun 2017 15:49:41 +0200
Original-Received: by mail-qt0-f200.google.com with SMTP id z5sf64625172qta.12
        for <gclcip-std-proposals@m.gmane.org>; Tue, 13 Jun 2017 06:49:45 -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: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=iIkJRYN5mgMgwFOiKPr+VKYCbCpFxR5g2j8zgOTSd1c=;
        b=OhNyobOTEHHIy6vVIBqp/ZmpvQcWUlOdWQea2plXnCWNX3Qfsn6+N+iriJGEy0bjG8
         vilnTvTvk/K78LWKGKlUPHf+99R/vm9k1LxnAp0CKW7DxgearhGJ2zYrB4ZGyh7cUiaA
         gn8ftifx+03jNJdkKJeGyUvQsx53d1lej3DnmHzXHXte09xri9f16zy10pXIf8O7E0VM
         O2Zs6ZPX+LoofIa/kGysqKH8cZ4qSrkQErwZ7PPQUJlxcAsptquqOuvP7B9ZnYGyvMV5
         GoBL/9IxJoM6p3zoBksqY4mGIB6W/wFon9S+g9cHO14VwUMPdX3rgKCD1hQClcyb/lJE
         XZOg==
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: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=iIkJRYN5mgMgwFOiKPr+VKYCbCpFxR5g2j8zgOTSd1c=;
        b=nVuZXukZSOxWkj02HWWkiWTAiSw931QZAmj0rq6ybdNZdeUoy8DGDbfgY3werMEr0x
         VbRD0O4ZBXr2rUiL5Xtze+YuASeLs8zvEHay4ChJXrZITJS3IP/ycOtmfkEk31Mf1Dx/
         mDMwGyeWxBOfkjmPsvHGAo+M1oK4vxcuyOj5SBnur6kmBE2J1Ysi8/p0HboNPSDhdERm
         D4CxMGOnmO+zQVOoWU6ddLWWmN9GtpKHG1qGk7h8S7yY8uo8tmrGXVB29n4fCpvMTpMS
         3udfEOWVsxbu6X8fzYuGyLVOp7y2ajXLPP/hgEelVsRaeqQlMZw3F5V3Xn+wfxm/SvOF
         gjrQ==
X-Gm-Message-State: AKS2vOxGgHBM16oBG6SkZ6ILOsIUwiWaxQ4hYx/ltRsxOPsrfqbU0ZDC
	Q85XA2CtHdfthPWV
X-Received: by 10.200.49.195 with SMTP id i3mr2740536qte.63.1497361784793;
        Tue, 13 Jun 2017 06:49:44 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.157.13.231 with SMTP id 94ls16784568ots.32.gmail; Tue, 13 Jun
 2017 06:49:43 -0700 (PDT)
X-Received: by 10.157.12.161 with SMTP id b30mr75057otb.3.1497361783605;
        Tue, 13 Jun 2017 06:49:43 -0700 (PDT)
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:32752
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/32752>

------=_Part_1692_922395550.1497361782856
Content-Type: multipart/alternative; 
	boundary="----=_Part_1693_3519812.1497361782857"

------=_Part_1693_3519812.1497361782857
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

*Introduction*

This thread is an update version for "Adding the Keyword "proxy" in C++=20
<https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/kvkgsHM=
6wFQ>"=20
and "Adding the Keyword "interface" in C++=20
<https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/uyfpeyE=
yW4o>
".

After a short term discussion, Mr. Bengt Gustafsson and I have come up with=
=20
a better solution to decouple implementations from requirements of=20
polymorphism. Comparing to the previous two solutions, not only does this=
=20
solution can be used wherever the two solutions are suitable for, but also=
=20
has more reasonable architecture and does not require new syntax.

Andrea Proli's paper about "Dynamic Generic Programming with Virtual=20
Concepts=20
<https://github.com/andyprowl/virtual-concepts/blob/master/draft/Dynamic%20=
Generic%20Programming%20with%20Virtual%20Concepts.pdf>"=20
is a very enlightening proposal and aims to solve the same challenge as=20
this solution does, and it has already clarified the motivation of this=20
work. However, I think there is still some room to improve. "DGPVC" is used=
=20
to refer to this paper in the following sections.

*Design Goals*


   - Efficiency: If this feature is properly used, the performance shall=20
   not be lower than a hand-wrote implementation without this feature for a=
=20
   same requirement.
   - Support for different lifetime management strategies: including but=20
   not limited to reference semantics, value semantics, shared semantics, C=
OW=20
   (Copy On Write)=E3=80=81SOO (Small Object Optimization, aka SBO, Small B=
uffer=20
   Optimization) and other known advanced GC algorithms.
   - Ease of use: a type-erased type shall behave as the concrete type.
   - Not violate the rule of the type system: a type-erased type shall be a=
=20
   standard-layout class.
  =20

*Design Decisions*


   - The type requirements shall be specified by a pure-virtual class.
  =20
In my earlier post, some feedback suggests that it will be elegant to=20
specify type requirements with the Concepts TS. DGPVC is a solution that=20
adopts this. However, on the one hand, it introduces new syntax, mixing the=
=20
"concepts" with the "virtual qualifier", which makes the types ambiguous.=
=20
From the code snippets included in the paper, we can tell that "virtual=20
concept" is an "auto-generated" type. Comparing to introducing new syntax,=
=20
I prefer to make it a "magic class template", which at least "looks like a=
=20
type" and much easier to understand. On the other hand, I haven't seen much=
=20
about how to implement the entire solution introduced in DGPVC, and it=20
remains hard for me to imagine how are we supposed to implement for the=20
expressions that cannot be declared virtual, e.g. friend functions that=20
take values of the concrete type as parameters.

   - The lifetime management strategies shall be specified by a type having=
=20
   the "Wrapper" semantics.
  =20
The "Wrapper" semantics is associated with the responsibility for=20
addressing, and may have different lifetime management strategies. It seems=
=20
difficult to extend DGPVC with other lifetime management strategies as it=
=20
only support the basic "reference semantics" and "value semantics", e.g.=20
reference-counting based algorithm and more complicated GC algorithms. In=
=20
this solution, users are free to specify different types of wrapper for any=
=20
lifetime management requirements. Besides, I think it is rude to couple the=
=20
"characteristics for construction and destruction" with other expressions=
=20
required in DGPVC. When it is not required to manage the lifetime issue=20
(e.g.,with reference semantics), the constraints related to constructors=20
and destructors are redundant; conversely, when we need value semantics, it=
=20
is natural that the type being type-eraing shall be at least=20
MoveConstructible most of the time. This problem does not exist in my=20
solution as constructors and destructors are not able to declared pure=20
virtual, and a wrapper type may carry such constraints if necessary.

   - The type-erased type shall be a specification of a class template,=20
   which is duck-typed by the compiler.
   - When calling a specific member function of a type-erased type, the=20
   parameters shall be forwarded to a "conversion table".
  =20
Unlike std::function<R(Args...)> that provide a standard version of "R=20
operator()(Args...)", I think it is much general to provide the routine=20
that forward any parameter to the standard conversion table, e.g.,=20
providing "template <class... _Args> R operator()(_Args&&...)" instead of=
=20
"R operator()(Args...)". This will not have effects on the function itself,=
=20
and it is friendly for the "standard" conversion table.

*Technical Specifications*

*Wrapper requirements*

A type W meets the Wrapper requirements if the following expressions are=20
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.

*Class template proxy*

Expression "proxy<I, W>" is a well-formed type if I is a pure virtual class=
=20
(without a virtual destructor) and W is a type meets the Wrapper=20
requirements defined above.

"proxy<I, W>" is MoveConstructible if W is MoveConstructible, while=20
"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,=20
"p.f(args...)" shall be a valid expression if "(*i).f(args...)" is a valid=
=20
expression, where f is any valid function name (including operator=20
overloads) and "args..." is any valid combination of values of any type.

*Prototypes for Wrappers*

Class "SharedWrapper" (with shared semantics), class template "DeepWrapper"=
=20
(with value semantics and SOO feature) and class "DefferedWrapper" (with=20
reference semantics) are designed to meet the Wrapper requirements.=20
Possible implementation is included in the attachments.

*Code Generation*

Take the "Callable" interface as an example,

template <class T>
class Callable; // undefined

/* Interface declaration with pure virtual class */
template <class R, class... Args>
class Callable<R(Args...)> {
 public:
  virtual R operator()(Args... args) =3D 0;
};

The code that the compiler will possibly generate for the type=20
"proxy<Callable<R(Args...)>, W>" is as shown below:

#include <system_error>

/* Auto generated specialization for proxy<Callable<R(Args...)>, W> */
template <class R, class... Args, class W> requires Wrapper<W>()
class proxy<Callable<R(Args...)>, W> {
 public:
  /* Construct with a value of any type */
  /* More concepts may be required to check whether T is suitable for this=
=20
interface */
  template <class T>
  proxy(T&& data) requires
      !std::is_same<std::remove_cv_t<std::remove_reference_t<T>>,=20
proxy>::value &&
      requires(T t, Args&&... args) { { t(std::forward<Args>(args)...) } ->=
=20
R; }
      { init(std::forward<T>(data)); }

  /* Default constructor */
  proxy() { init(); }

  /* Move constructor */
  proxy(proxy&& lhs) { lhs.move_init(*this); }

  /* Copy constructor */
  proxy(const proxy& rhs) { rhs.copy_init(*this); }

  /* Destructor */
  ~proxy() { deinit(); }

  proxy& operator=3D(const proxy& rhs) {
    deinit();
    rhs.copy_init(*this);
    return *this;
  }

  proxy& operator=3D(proxy&& lhs) {
    deinit();
    lhs.move_init(*this);
    return *this;
  }

  template <class T>
  proxy& operator=3D(T&& data) requires
      !std::is_same<std::remove_cv_t<std::remove_reference_t<T>>,=20
proxy>::value {
    deinit();
    init(std::forward<T>(data));
    return *this;
  }

  /* Auto generated member function */
  /* (Args...) !=3D (_Args...), args... shall be forwarded to the virtual=
=20
function */
  template <class... _Args>
  R operator()(_Args&&... args) {
    // Call the target function with polymorphism
    return=20
(*reinterpret_cast<Abstraction*>(data_.get()))(std::forward<_Args>(args)...=
);
  }

 private:
  /* Base class, extending the original interface */
  class Abstraction : public Callable<R(Args...)> {
   public:
    Abstraction() =3D default;

    /* Initialize the wrapper */
    template <class T>
    Abstraction(T&& data) : wrapper_(std::forward<T>(data)) {}

    /* Non-virtual copy construct */
    void copy_init(void* mem) const {
      /* Copy the pointer of the vtable */
      memcpy(mem, this, sizeof(Callable<R(Args...)>));

      /* Initialize the wrapper with lvalue */
      new (&reinterpret_cast<Abstraction*>(mem)->wrapper_) W(wrapper_);
    }

    void move_init(void* mem) {
      memcpy(mem, this, sizeof(Callable<R(Args...)>));
      new (&reinterpret_cast<Abstraction*>(mem)->wrapper_)=20
W(std::move(wrapper_));
    }

    W wrapper_; // A type-erased wrapper
  };

  /* A placeholder for the uninitialized state */
  class Uninitialized : public Abstraction {
   public:
    /* Only for demonstration */
    R operator()(Args...) override {
      throw std::runtime_error("Using uninitialized proxy");
    }
  };

  /* Type-specific implementation */
  template <class T>
  class Implementation : public Abstraction {
   public:
    template <class U>
    Implementation(U&& data) : Abstraction(std::forward<U>(data)) {}

    R operator()(Args... args) override {
      /* Restore the type and call the target function */
      return=20
(*reinterpret_cast<T*>(this->wrapper_.get()))(std::forward<Args>(args)...);
    }
  };

  void init() {
    new (reinterpret_cast<Uninitialized*>(data_.get())) Uninitialized();
  }

  /* Initialize with a concrete type and value */
  template <class T>
  void init(T&& data) {
    new=20
(reinterpret_cast<Implementation<std::remove_reference_t<T>>*>(data_.get())=
)
        Implementation<std::remove_reference_t<T>>(std::forward<T>(data));
  }

  /* Copy semantics */
  void copy_init(proxy& rhs) const {
    // Forward this operation
    reinterpret_cast<const=20
Abstraction*>(data_.get())->copy_init(rhs.data_.get());
  }

  /* Move semantics */
  void move_init(proxy& rhs) {
    // Forward this operation
    reinterpret_cast<Abstraction*>(data_.get())->move_init(rhs.data_.get())=
;
  }

  /* Destroy semantics */
  void deinit() {
    // Forward this operation
    reinterpret_cast<Abstraction*>(data_.get())->~Abstraction();
  }

  /* sizeof(Uninitialized) =3D=3D sizeof(ptrdiff_t) + sizeof(W) */
  MemoryBlock<sizeof(Uninitialized)> data_;
};

*Examples*

The following code is well-formed with the class template "Callable"=20
defined above:

#include <cmath>

#include "proxy.hpp"

int main() {
  DeepProxy<Callable<void()>> a([] { puts("Lambda Expression 1"); });
  a();

  SharedProxy<Callable<int(int)>> b(&std::abs<int>);
  printf("%d\n", b(-2));

  auto lambda_2 =3D [] { puts("Lambda Expression 2"); };
  DefferedProxy<Callable<void()>> c(lambda_2);
  c();
  c =3D a;
  c();

  return 0;
}

I am looking forward to your comments and suggestions!

Thank you!

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/8d79a013-fe0e-4fb6-8278-d438ae9b4c64%40isocpp.or=
g.

------=_Part_1693_3519812.1497361782857
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div><font size=3D"6"><b>Introduction</b></font></div><div=
><br></div><div>This thread is an update version for &quot;<a href=3D"https=
://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/kvkgsHM6wFQ">=
Adding the Keyword &quot;proxy&quot; in C++</a>&quot; and &quot;<a href=3D"=
https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/uyfpeyEy=
W4o">Adding the Keyword &quot;interface&quot; in C++</a>&quot;.</div><div><=
br></div><div>After a short term discussion, Mr. Bengt Gustafsson and I hav=
e come up with a better solution to decouple implementations from requireme=
nts of polymorphism. Comparing to the previous two solutions, not only does=
 this solution can be used wherever the two solutions are suitable for, but=
 also has more reasonable architecture and does not require new syntax.</di=
v><div><br></div><div>Andrea Proli&#39;s paper about &quot;<a href=3D"https=
://github.com/andyprowl/virtual-concepts/blob/master/draft/Dynamic%20Generi=
c%20Programming%20with%20Virtual%20Concepts.pdf">Dynamic Generic Programmin=
g with Virtual Concepts</a>&quot; is a very enlightening proposal and aims =
to solve the same challenge as this solution does, and it has already clari=
fied the motivation of this work. However, I think there is still some room=
 to improve. &quot;DGPVC&quot; is used to refer to this paper in the follow=
ing sections.</div><div><br></div><div><font size=3D"6"><b>Design Goals</b>=
</font></div><div><br></div><div><ul><li>Efficiency: If this feature is pro=
perly used, the performance shall not be lower than a hand-wrote implementa=
tion without this feature for a same requirement.<br></li><li>Support for d=
ifferent lifetime management strategies: including but not limited to refer=
ence semantics, value semantics, shared semantics, COW (Copy On Write)=E3=
=80=81SOO (Small Object Optimization, aka SBO, Small Buffer Optimization) a=
nd other known advanced GC algorithms.<br></li><li>Ease of use: a type-eras=
ed type shall behave as the concrete type.<br></li><li>Not violate the rule=
 of the type system: a type-erased type shall be a standard-layout class.<b=
r></li></ul></div><div><br></div><div><font size=3D"6"><b>Design Decisions<=
/b></font></div><div><br></div><div><ul><li>The type requirements shall be =
specified by a pure-virtual class.<br></li></ul></div><div>In my earlier po=
st, some feedback suggests that it will be elegant to specify type requirem=
ents with the Concepts TS. DGPVC is a solution that adopts this. However, o=
n the one hand, it introduces new syntax, mixing the &quot;concepts&quot; w=
ith the &quot;virtual qualifier&quot;, which makes the types ambiguous. Fro=
m the code snippets included in the paper, we can tell that &quot;virtual c=
oncept&quot; is an &quot;auto-generated&quot; type. Comparing to introducin=
g new syntax, I prefer to make it a &quot;magic class template&quot;, which=
 at least &quot;looks like a type&quot; and much easier to understand. On t=
he other hand, I haven&#39;t seen much about how to implement the entire so=
lution introduced in DGPVC, and it remains hard for me to imagine how are w=
e supposed to implement for the expressions that cannot be declared virtual=
, e.g. friend functions that take values of the concrete type as parameters=
..</div><div><ul><li>The lifetime management strategies shall be specified b=
y a type having the &quot;Wrapper&quot; semantics.<br></li></ul></div><div>=
The &quot;Wrapper&quot; semantics is associated with the responsibility for=
 addressing, and may have different lifetime management strategies. It seem=
s difficult to extend DGPVC with other lifetime management strategies as it=
 only support the basic &quot;reference semantics&quot; and &quot;value sem=
antics&quot;, e.g. reference-counting based algorithm and more complicated =
GC algorithms. In this solution, users are free to specify different types =
of wrapper for any lifetime management requirements. Besides, I think it is=
 rude to couple the &quot;characteristics for construction and destruction&=
quot; with other expressions required in DGPVC. When it is not required to =
manage the lifetime issue (e.g.,with reference semantics), the constraints =
related to constructors and destructors are redundant; conversely, when we =
need value semantics, it is natural that the type being type-eraing shall b=
e at least MoveConstructible most of the time. This problem does not exist =
in my solution as constructors and destructors are not able to declared pur=
e virtual, and a wrapper type may carry such constraints if necessary.</div=
><div><ul><li>The type-erased type shall be a specification of a class temp=
late, which is duck-typed by the compiler.<br></li><li>When calling a speci=
fic member function of a type-erased type, the parameters shall be forwarde=
d to a &quot;conversion table&quot;.<br></li></ul></div><div>Unlike std::fu=
nction&lt;R(Args...)&gt; that provide a standard version of &quot;R operato=
r()(Args...)&quot;, I think it is much general to provide the routine that =
forward any parameter to the standard conversion table, e.g., providing &qu=
ot;template &lt;class... _Args&gt; R operator()(_Args&amp;&amp;...)&quot; i=
nstead of &quot;R operator()(Args...)&quot;. This will not have effects on =
the function itself, and it is friendly for the &quot;standard&quot; conver=
sion table.</div><div><br></div><div><font size=3D"6"><b>Technical Specific=
ations</b></font></div><div><br></div><div><font size=3D"4"><b>Wrapper requ=
irements</b></font></div><div><br></div><div>A type W meets the Wrapper req=
uirements if the following expressions are well-formed and have the specifi=
c semantics (w denotes a value of type W).</div><div><br></div><div>w.get()=
</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">	</span=
>Requires: w is initialized with an object.</div><div><span class=3D"Apple-=
tab-span" style=3D"white-space:pre">	</span>Effects: acquires the pointer o=
f the wrapped object if there is one.</div><div><span class=3D"Apple-tab-sp=
an" style=3D"white-space:pre">	</span>Return type: void*.</div><div><span c=
lass=3D"Apple-tab-span" style=3D"white-space:pre">	</span>Returns: a pointe=
r of the wrapped object.</div><div><br></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 class (witho=
ut a virtual destructor) and W is a type meets the Wrapper requirements def=
ined above.</div><div><br></div><div>&quot;proxy&lt;I, W&gt;&quot; is MoveC=
onstructible if W is MoveConstructible, while &quot;proxy&lt;I, W&gt;&quot;=
 is CopyConstructible if W is CopyConstructible.</div><div><br></div><div>P=
roviding p is a value of &quot;proxy&lt;I, W&gt;&quot; and i is a pointer o=
f I, &quot;p.f(args...)&quot; shall be a valid expression if &quot;(*i).f(a=
rgs...)&quot; is a valid expression, where f is any valid function name (in=
cluding operator overloads) and &quot;args...&quot; is any valid combinatio=
n of values of any type.</div><div><br></div><div><b><font size=3D"4">Proto=
types for Wrappers</font></b></div><div><br></div><div>Class &quot;SharedWr=
apper&quot; (with shared semantics), class template &quot;DeepWrapper&quot;=
 (with value semantics and SOO feature) and class &quot;DefferedWrapper&quo=
t; (with reference semantics) are designed to meet the Wrapper requirements=
.. Possible implementation is included in the attachments.</div><div><br></d=
iv><div><font size=3D"6"><b>Code Generation</b></font></div><div><br></div>=
<div>Take the &quot;Callable&quot; interface as an example,</div><div><br><=
/div><div><div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 18=
7, 187); word-wrap: break-word; background-color: rgb(250, 250, 250);"><cod=
e class=3D"prettyprint"><div class=3D"subprettyprint"><font color=3D"#66006=
6"><div class=3D"subprettyprint">template &lt;class T&gt;</div><div class=
=3D"subprettyprint">class Callable; // undefined</div><div class=3D"subpret=
typrint"><br></div><div class=3D"subprettyprint">/* Interface declaration w=
ith pure virtual class */</div><div class=3D"subprettyprint">template &lt;c=
lass R, class... Args&gt;</div><div class=3D"subprettyprint">class Callable=
&lt;R(Args...)&gt; {</div><div class=3D"subprettyprint">=C2=A0public:</div>=
<div class=3D"subprettyprint">=C2=A0 virtual R operator()(Args... args) =3D=
 0;</div><div class=3D"subprettyprint">};</div></font></div></code></div></=
div><div><br></div><div>The code that the compiler will possibly generate f=
or the type &quot;proxy&lt;Callable&lt;R(Args...)&gt;, W&gt;&quot; is as sh=
own below:</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">#include &lt;sys=
tem_error&gt;</div><div class=3D"subprettyprint"><br></div><div class=3D"su=
bprettyprint">/* Auto generated specialization for proxy&lt;Callable&lt;R(A=
rgs...)&gt;, W&gt; */</div><div class=3D"subprettyprint">template &lt;class=
 R, class... Args, class W&gt; requires Wrapper&lt;W&gt;()</div><div class=
=3D"subprettyprint">class proxy&lt;Callable&lt;R(Args...)&gt;, W&gt; {</div=
><div class=3D"subprettyprint">=C2=A0public:</div><div class=3D"subprettypr=
int">=C2=A0 /* Construct with a value of any type */</div><div class=3D"sub=
prettyprint">=C2=A0 /* More concepts may be required to check whether T is =
suitable for this interface */</div><div class=3D"subprettyprint">=C2=A0 te=
mplate &lt;class T&gt;</div><div class=3D"subprettyprint">=C2=A0 proxy(T&am=
p;&amp; data) requires</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=
=A0 !std::is_same&lt;std::remove_cv_t&lt;std::remove_reference_t&lt;T&gt;&g=
t;, proxy&gt;::value &amp;&amp;</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0 =C2=A0 requires(T t, Args&amp;&amp;... args) { { t(std::forward&lt;A=
rgs&gt;(args)...) } -&gt; R; }</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0 =C2=A0 { init(std::forward&lt;T&gt;(data)); }</div><div class=3D"sub=
prettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Default cons=
tructor */</div><div class=3D"subprettyprint">=C2=A0 proxy() { init(); }</d=
iv><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=
=C2=A0 /* Move constructor */</div><div class=3D"subprettyprint">=C2=A0 pro=
xy(proxy&amp;&amp; lhs) { lhs.move_init(*this); }</div><div class=3D"subpre=
ttyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Copy constructo=
r */</div><div class=3D"subprettyprint">=C2=A0 proxy(const proxy&amp; rhs) =
{ rhs.copy_init(*this); }</div><div class=3D"subprettyprint"><br></div><div=
 class=3D"subprettyprint">=C2=A0 /* Destructor */</div><div class=3D"subpre=
ttyprint">=C2=A0 ~proxy() { deinit(); }</div><div class=3D"subprettyprint">=
<br></div><div class=3D"subprettyprint">=C2=A0 proxy&amp; operator=3D(const=
 proxy&amp; rhs) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 deinit(=
);</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 rhs.copy_init(*this);</=
div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return *this;</div><div cla=
ss=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br></div=
><div class=3D"subprettyprint">=C2=A0 proxy&amp; operator=3D(proxy&amp;&amp=
; lhs) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 deinit();</div><d=
iv class=3D"subprettyprint">=C2=A0 =C2=A0 lhs.move_init(*this);</div><div c=
lass=3D"subprettyprint">=C2=A0 =C2=A0 return *this;</div><div class=3D"subp=
rettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br></div><div clas=
s=3D"subprettyprint">=C2=A0 template &lt;class T&gt;</div><div class=3D"sub=
prettyprint">=C2=A0 proxy&amp; operator=3D(T&amp;&amp; data) requires</div>=
<div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 !std::is_same&lt;std::re=
move_cv_t&lt;std::remove_reference_t&lt;T&gt;&gt;, proxy&gt;::value {</div>=
<div class=3D"subprettyprint">=C2=A0 =C2=A0 deinit();</div><div class=3D"su=
bprettyprint">=C2=A0 =C2=A0 init(std::forward&lt;T&gt;(data));</div><div cl=
ass=3D"subprettyprint">=C2=A0 =C2=A0 return *this;</div><div class=3D"subpr=
ettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">=C2=A0 /* Auto generated member function */</div><div c=
lass=3D"subprettyprint">=C2=A0 /* (Args...) !=3D (_Args...), args... shall =
be forwarded to the virtual function */</div><div class=3D"subprettyprint">=
=C2=A0 template &lt;class... _Args&gt;</div><div class=3D"subprettyprint">=
=C2=A0 R operator()(_Args&amp;&amp;... args) {</div><div class=3D"subpretty=
print">=C2=A0 =C2=A0 // Call the target function with polymorphism</div><di=
v class=3D"subprettyprint">=C2=A0 =C2=A0 return (*reinterpret_cast&lt;Abstr=
action*&gt;(data_.get()))(std::forward&lt;_Args&gt;(args)...);</div><div cl=
ass=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br></di=
v><div class=3D"subprettyprint">=C2=A0private:</div><div class=3D"subpretty=
print">=C2=A0 /* Base class, extending the original interface */</div><div =
class=3D"subprettyprint">=C2=A0 class Abstraction : public Callable&lt;R(Ar=
gs...)&gt; {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0public:</div><=
div class=3D"subprettyprint">=C2=A0 =C2=A0 Abstraction() =3D default;</div>=
<div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 /* Initialize the wrapper */</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 template &lt;class T&gt;</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 Abstraction(T&amp;&amp; data) : wrapper_(std::forward&lt;T&gt=
;(data)) {}</div><div class=3D"subprettyprint"><br></div><div class=3D"subp=
rettyprint">=C2=A0 =C2=A0 /* Non-virtual copy construct */</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 void copy_init(void* mem) const {</div><d=
iv class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 /* Copy the pointer of the=
 vtable */</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 memcpy(m=
em, this, sizeof(Callable&lt;R(Args...)&gt;));</div><div class=3D"subpretty=
print"><br></div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 /* Init=
ialize the wrapper with lvalue */</div><div class=3D"subprettyprint">=C2=A0=
 =C2=A0 =C2=A0 new (&amp;reinterpret_cast&lt;Abstraction*&gt;(mem)-&gt;wrap=
per_) W(wrapper_);</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 }</div>=
<div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 void move_init(void* mem) {</div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 =C2=A0 memcpy(mem, this, sizeof(Callable&lt;R(Args...)&gt;));=
</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 new (&amp;reinterp=
ret_cast&lt;Abstraction*&gt;(mem)-&gt;wrapper_) W(std::move(wrapper_));</di=
v><div class=3D"subprettyprint">=C2=A0 =C2=A0 }</div><div class=3D"subprett=
yprint"><br></div><div class=3D"subprettyprint">=C2=A0 =C2=A0 W wrapper_; /=
/ A type-erased wrapper</div><div class=3D"subprettyprint">=C2=A0 };</div><=
div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0=
 /* A placeholder for the uninitialized state */</div><div class=3D"subpret=
typrint">=C2=A0 class Uninitialized : public Abstraction {</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0public:</div><div class=3D"subprettyprint"=
>=C2=A0 =C2=A0 /* Only for demonstration */</div><div class=3D"subprettypri=
nt">=C2=A0 =C2=A0 R operator()(Args...) override {</div><div class=3D"subpr=
ettyprint">=C2=A0 =C2=A0 =C2=A0 throw std::runtime_error(&quot;Using uninit=
ialized proxy&quot;);</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 }</d=
iv><div class=3D"subprettyprint">=C2=A0 };</div><div class=3D"subprettyprin=
t"><br></div><div class=3D"subprettyprint">=C2=A0 /* Type-specific implemen=
tation */</div><div class=3D"subprettyprint">=C2=A0 template &lt;class T&gt=
;</div><div class=3D"subprettyprint">=C2=A0 class Implementation : public A=
bstraction {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0public:</div><=
div class=3D"subprettyprint">=C2=A0 =C2=A0 template &lt;class U&gt;</div><d=
iv class=3D"subprettyprint">=C2=A0 =C2=A0 Implementation(U&amp;&amp; data) =
: Abstraction(std::forward&lt;U&gt;(data)) {}</div><div class=3D"subprettyp=
rint"><br></div><div class=3D"subprettyprint">=C2=A0 =C2=A0 R operator()(Ar=
gs... args) override {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=
=A0 /* Restore the type and call the target function */</div><div class=3D"=
subprettyprint">=C2=A0 =C2=A0 =C2=A0 return (*reinterpret_cast&lt;T*&gt;(th=
is-&gt;wrapper_.get()))(std::forward&lt;Args&gt;(args)...);</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 }</div><div class=3D"subprettyprint">=C2=
=A0 };</div><div class=3D"subprettyprint"><br></div><div class=3D"subpretty=
print">=C2=A0 void init() {</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 new (reinterpret_cast&lt;Uninitialized*&gt;(data_.get())) Uninitialized=
();</div><div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprett=
yprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Initialize with a=
 concrete type and value */</div><div class=3D"subprettyprint">=C2=A0 templ=
ate &lt;class T&gt;</div><div class=3D"subprettyprint">=C2=A0 void init(T&a=
mp;&amp; data) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 new (rein=
terpret_cast&lt;Implementation&lt;std::remove_reference_t&lt;T&gt;&gt;*&gt;=
(data_.get()))</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 Implementation&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"subprettyprint">=C2=A0 /* Copy =
semantics */</div><div class=3D"subprettyprint">=C2=A0 void copy_init(proxy=
&amp; rhs) const {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // Forw=
ard this operation</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 reinter=
pret_cast&lt;const Abstraction*&gt;(data_.get())-&gt;copy_init(rhs.data_.ge=
t());</div><div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subpre=
ttyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Move semantics =
*/</div><div class=3D"subprettyprint">=C2=A0 void move_init(proxy&amp; rhs)=
 {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // Forward this operati=
on</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 reinterpret_cast&lt;Abs=
traction*&gt;(data_.get())-&gt;move_init(rhs.data_.get());</div><div class=
=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br></div><=
div class=3D"subprettyprint">=C2=A0 /* Destroy semantics */</div><div class=
=3D"subprettyprint">=C2=A0 void deinit() {</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 // Forward this operation</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 reinterpret_cast&lt;Abstraction*&gt;(data_.get())-&gt;~Abs=
traction();</div><div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"=
subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* sizeof(Un=
initialized) =3D=3D sizeof(ptrdiff_t) + sizeof(W) */</div><div class=3D"sub=
prettyprint">=C2=A0 MemoryBlock&lt;sizeof(Uninitialized)&gt; data_;</div><d=
iv class=3D"subprettyprint">};</div></font></div></code></div></div><div><b=
r></div><div><font size=3D"6"><b>Examples</b></font></div><div><br></div><d=
iv>The following code is well-formed with the class template &quot;Callable=
&quot; defined above:</div><div><br></div><div><div class=3D"prettyprint" s=
tyle=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; backgr=
ound-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"=
subprettyprint"><font color=3D"#660066"><div class=3D"subprettyprint">#incl=
ude &lt;cmath&gt;</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">#include &quot;proxy.hpp&quot;</div><div class=3D"subpr=
ettyprint"><br></div><div class=3D"subprettyprint">int main() {</div><div c=
lass=3D"subprettyprint">=C2=A0 DeepProxy&lt;Callable&lt;void()&gt;&gt; a([]=
 { puts(&quot;Lambda Expression 1&quot;); });</div><div class=3D"subprettyp=
rint">=C2=A0 a();</div><div class=3D"subprettyprint"><br></div><div class=
=3D"subprettyprint">=C2=A0 SharedProxy&lt;Callable&lt;int(int)&gt;&gt; b(&a=
mp;std::abs&lt;int&gt;);</div><div class=3D"subprettyprint">=C2=A0 printf(&=
quot;%d\n&quot;, b(-2));</div><div class=3D"subprettyprint"><br></div><div =
class=3D"subprettyprint">=C2=A0 auto lambda_2 =3D [] { puts(&quot;Lambda Ex=
pression 2&quot;); };</div><div class=3D"subprettyprint">=C2=A0 DefferedPro=
xy&lt;Callable&lt;void()&gt;&gt; c(lambda_2);</div><div class=3D"subprettyp=
rint">=C2=A0 c();</div><div class=3D"subprettyprint">=C2=A0 c =3D a;</div><=
div class=3D"subprettyprint">=C2=A0 c();</div><div class=3D"subprettyprint"=
><br></div><div class=3D"subprettyprint">=C2=A0 return 0;</div><div class=
=3D"subprettyprint">}</div></font></div></code></div><br><div>I am looking =
forward to your comments and suggestions!</div><div><br></div><div>Thank yo=
u!</div><div><br></div><div>Mingxin Wang</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/8d79a013-fe0e-4fb6-8278-d438ae9b4c64%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/8d79a013-fe0e-4fb6-8278-d438ae9b4c64=
%40isocpp.org</a>.<br />

------=_Part_1693_3519812.1497361782857--

------=_Part_1692_922395550.1497361782856
Content-Type: application/zip; name=src.zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=src.zip
X-Attachment-Id: 99b06136-3b52-406e-b6ec-8455c1a6a852
Content-ID: <99b06136-3b52-406e-b6ec-8455c1a6a852>

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
6nNI5NIBUEsFBgAAAAAFAAUA6QEAAOwNAAAAAA==
------=_Part_1692_922395550.1497361782856--

.
