Topic: [std-proposals] Adding the Keyword interface i
Author: Mingxin Wang <wmx16835vv@163.com>
Date: Sun, 7 May 2017 22:23:12 -0700 (PDT)
Raw View
------=_Part_1491_1554325809.1494220992770
Content-Type: multipart/alternative;
boundary="----=_Part_1492_1896983442.1494220992771"
------=_Part_1492_1896983442.1494220992771
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Motivation
It is acknowledged that =E2=80=9C*Polymorphism*=E2=80=9D is fundamental in =
OO programming,=20
which is a method of runtime type abstraction. Suppose we are to build a=20
*threadpool*, and the tasks to be submitted may have different types, such=
=20
as lambda expressions, functors, function pointers, etc., thus runtime type=
=20
abstraction is required. A direct solution is to use =E2=80=9C
*std::function<void()>*=E2=80=9D to wrap each task, but it is *NOT *suitabl=
e for=20
only =E2=80=9C*MoveConstructible*=E2=80=9D ones, e.g., =E2=80=9C*std::packa=
ged_task<...>*=E2=80=9D. This=20
implementation (
https://github.com/progschj/ThreadPool/blob/master/ThreadPool.h) introduces=
=20
another =E2=80=9C*std::shared_ptr*=E2=80=9D and a lambda expression to make=
a =E2=80=9C
*std::packaged_task<...>*=E2=80=9D =E2=80=9C*CopyConstructible*=E2=80=9D, a=
nd also introduces extra=20
runtime overhead. Besides, *any unnecessary polymorphism have adverse=20
effects on runtime performance*, e.g., in this case, copying the object=20
with =E2=80=9C*operator=3D(const function&)*=E2=80=9D and =E2=80=9C*functio=
n(const function&)*=E2=80=9D are=20
not used but likely to introduce extra runtime overhead.
Sometimes we just want to convert different types into a same type with=20
runtime type abstraction, and this usually happens when storing them,=20
rather than calling a template function with them. More use cases can be=20
found in *my earlier post* (
https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/tQb9t6Hn=
u6M,=20
see class template =E2=80=9C*ThreadPool*=E2=80=9D (portal.hpp), class templ=
ate =E2=80=9C
*MultiPhaseConcurrentCallable*=E2=80=9D (concurrent_callable.hpp), class te=
mplate =E2=80=9C
*ConcurrentCaller1D*=E2=80=9D (concurrent_caller.hpp), etc.). That the reas=
on way I=20
tend to add the keyword =E2=80=9Cinterface=E2=80=9D in C++.
Expressions
With the keyword =E2=80=9C*interface*=E2=80=9D, users are encouraged to def=
ine runtime=20
abstractions like this (public by default):
interface Runnable {
void operator()();
};
After definition, =E2=80=9C*Runnable*=E2=80=9D is declared as a typename, a=
nd types that=20
meet the requirements are convertible to =E2=80=9C*Runnable*=E2=80=9D impli=
citly. The=20
interface to submit tasks may be implemented like this:
template <class F, class... Args>
void submit(F&& f, Args&&... args) const {
// bind_simple behaves like std::bind, but will forward the parameters as=
=20
rvalues rather than lvalues when calling =E2=80=9Cf=E2=80=9D
pool_->emplace(bind_simple(std::forward<F>(f),=20
std::forward<Args>(args)...));
}
What =E2=80=9C*bind_simple*=E2=80=9D returns is convertible to =E2=80=9C*Ru=
nnable*=E2=80=9D providing=20
*F(Args&&...)* is a valid expression, no matter whether F is =E2=80=9C
*CopyConstructible*=E2=80=9D.
An interface may inherit from any number of other interfaces providing=20
every expression is *unique*, e.g.:
interface BasicLockable {
void lock();
void unlock();
};
interface Lockable : BasicLockable {
bool try_lock();
};
are valid expressions, while:
interface A {
void f();
};
interface B {
void f();
};
interface C : A, B {};
are invalid expressions.
Possible implementation
In C++, the use of polymorphism is usually accompanied by pointers and=20
virtual member functions. In most cases, raw pointers are the last things=
=20
we want to program with, because pointers can have polymorphism mechanism=
=20
and may increase the risk of memory leak. That is probably the main reason=
=20
why =E2=80=9C*std::unique_ptr*=E2=80=9D and =E2=80=9C*std::shared_ptr*=E2=
=80=9D are introduced in the=20
standard.
This feature requires compiler support in parsing and code generation.=20
Complier may implement the feature with =E2=80=9C*std::unique_ptr*=E2=80=9D=
if it is=20
unnecessary to be =E2=80=9C*CopyConstructible*=E2=80=9D, or with =E2=80=9C*=
std::shared_ptr*=E2=80=9D=20
otherwise.
For the =E2=80=9C*Runnable*=E2=80=9D interface used in a threadpool impleme=
ntation, the=20
following code with =E2=80=9C*std::unique_ptr*=E2=80=9D may be generated au=
tomatically=20
(providing *Concepts TS* is supported):
class Runnable {
public:
template <class Data>
Runnable(Data data) requires
requires(Data data) { { data() }; }
: data_(new Implementation<Data>(std::move(data))) {}
Runnable() =3D default;
Runnable(Runnable&&) =3D default;
Runnable(const Runnable&) =3D delete;
Runnable& operator=3D(Runnable&&) =3D default;
Runnable& operator=3D(const Runnable&) =3D delete;
void operator()() { data_->op_0(); }
private:
class Abstraction {
public:
virtual void op_0() =3D 0;
virtual ~Abstraction() {}
};
template <class Data>
class Implementation final : public Abstraction {
public:
Implementation(Data&& data) : data_(std::forward<Data>(data)) {}
void op_0() override { data_(); }
private:
Data data_;
};
std::unique_ptr<Abstraction> data_;
};
Whose class diagram is as follows:
<https://lh3.googleusercontent.com/-nCZsS4sj_68/WQ_-f0SSzCI/AAAAAAAAADA/Xie=
nHN-D9qMeRCBFPRSDxX3lFc9GJM7QgCLcB/s1600/123.png>
For *callable *types that are required to be =E2=80=9C*CopyConstructible*=
=E2=80=9D, the=20
following code with =E2=80=9C*std::shared_ptr*=E2=80=9D may be generated au=
tomatically:
template <class R, class... Args>
class Callable {
public:
template <class Data>
Callable(Data data) requires
requires(Data data, Args... args) { { data(std::move(args)...) } ->=
=20
R; }
: data_(new Implementation<Data>(std::move(data))) {}
Callable() =3D default;
Callable(Callable&&) =3D default;
Callable(const Callable&) =3D default;
Callable& operator=3D(Callable&&) =3D default;
Callable& operator=3D(const Callable&) =3D default;
void operator()(Args... args) { data_->op_0(std::move(args)...); }
private:
class Abstraction {
public:
virtual void op_0(Args&&...) =3D 0;
virtual ~Abstraction() {}
};
template <class Data>
class Implementation final : public Abstraction {
public:
Implementation(Data&& data) : data_(std::forward<Data>(data)) {}
void op_0(Args&&... args) override {=20
data_(std::forward<Args>(args)...); }
private:
Data data_;
};
std::shared_ptr<Abstraction> data_;
};
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/c8742174-fef0-44a9-988d-2c8aebba9243%40isocpp.or=
g.
------=_Part_1492_1896983442.1494220992771
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><span style=3D"font-family: georgia, serif; font-size=
: xx-large;">Motivation</span><br></div><div><font face=3D"georgia, serif" =
size=3D"2"><br></font></div><div><font face=3D"georgia, serif" size=3D"2">I=
t is acknowledged that =E2=80=9C<b>Polymorphism</b>=E2=80=9D is fundamental=
in OO programming, which is a method of runtime type abstraction. Suppose =
we are to build a <b>threadpool</b>, and the tasks to be submitted may have=
different types, such as lambda expressions, functors, function pointers, =
etc., thus runtime type abstraction is required. A direct solution is to us=
e =E2=80=9C<b>std::function<void()></b>=E2=80=9D to wrap each task, b=
ut it is <b>NOT </b>suitable for only =E2=80=9C<b>MoveConstructible</b>=E2=
=80=9D ones, e.g., =E2=80=9C<b>std::packaged_task<...></b>=E2=80=9D. =
This implementation (<a href=3D"https://github.com/progschj/ThreadPool/blob=
/master/ThreadPool.h">https://github.com/progschj/ThreadPool/blob/master/Th=
readPool.h</a>) introduces another =E2=80=9C<b>std::shared_ptr</b>=E2=80=9D=
and a lambda expression to make a =E2=80=9C<b>std::packaged_task<...>=
;</b>=E2=80=9D =E2=80=9C<b>CopyConstructible</b>=E2=80=9D, and also introdu=
ces extra runtime overhead. Besides, <b>any unnecessary polymorphism have a=
dverse effects on runtime performance</b>, e.g., in this case, copying the =
object with =E2=80=9C<b>operator=3D(const function&)</b>=E2=80=9D and =
=E2=80=9C<b>function(const function&)</b>=E2=80=9D are not used but lik=
ely to introduce extra runtime overhead.<br></font></div><div><font face=3D=
"georgia, serif" size=3D"2"><br></font></div><div><font face=3D"georgia, se=
rif" size=3D"2">Sometimes we just want to convert different types into a sa=
me type with runtime type abstraction, and this usually happens when storin=
g them, rather than calling a template function with them. More use cases c=
an be found in <b>my earlier post</b> (<a href=3D"https://groups.google.com=
/a/isocpp.org/forum/#!topic/std-proposals/tQb9t6Hnu6M">https://groups.googl=
e.com/a/isocpp.org/forum/#!topic/std-proposals/tQb9t6Hnu6M</a>, see class t=
emplate =E2=80=9C<b>ThreadPool</b>=E2=80=9D (portal.hpp), class template =
=E2=80=9C<b>MultiPhaseConcurrentCallable</b>=E2=80=9D (concurrent_callable.=
hpp), class template =E2=80=9C<b>ConcurrentCaller1D</b>=E2=80=9D (concurren=
t_caller.hpp), etc.). That the reason way I tend to add the keyword =E2=80=
=9Cinterface=E2=80=9D in C++.<br></font></div><div><font face=3D"georgia, s=
erif" size=3D"2"><br></font></div><div><font face=3D"georgia, serif"><font =
size=3D"6">Expressions</font><br></font></div><div><font face=3D"georgia, s=
erif" size=3D"2"><br></font></div><div><font face=3D"georgia, serif" size=
=3D"2">With the keyword =E2=80=9C<b>interface</b>=E2=80=9D, users are encou=
raged to define runtime abstractions like this (public by default):<br></fo=
nt></div><div><font face=3D"georgia, serif" size=3D"2"><br></font></div><di=
v><font face=3D"georgia, serif" size=3D"2"><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"><div class=3D"subprettyprint">interface Runnable {</div><div cl=
ass=3D"subprettyprint">=C2=A0 void operator()();</div><div class=3D"subpret=
typrint">};</div></div></code></div><br>After definition, =E2=80=9C<b>Runna=
ble</b>=E2=80=9D is declared as a typename, and types that meet the require=
ments are convertible to =E2=80=9C<b>Runnable</b>=E2=80=9D implicitly. The =
interface to submit tasks may be implemented like this:<br></font></div><di=
v><font face=3D"georgia, serif" size=3D"2"><br></font></div><div><font face=
=3D"georgia, serif" size=3D"2"><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">=
<p class=3D"MsoNormal"><span lang=3D"EN-US">template <class F, class... =
Args><o:p></o:p></span></p>
<p class=3D"MsoNormal"><span lang=3D"EN-US">void submit(F&& f,
Args&&... args) const {<o:p></o:p></span></p>
<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0 //
bind_simple behaves like std::bind, but will forward the parameters as rval=
ues
rather than lvalues when calling =E2=80=9Cf=E2=80=9D<o:p></o:p></span></p>
<p class=3D"MsoNormal"><span lang=3D"EN-US">=C2=A0
pool_->emplace(bind_simple(std::forward<F>(f),
std::forward<Args>(args)...));<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:
"Times New Roman",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"=
>}</span><br></div></code></div><br>What =E2=80=9C<b>bind_simple</b>=E2=80=
=9D returns is convertible to =E2=80=9C<b>Runnable</b>=E2=80=9D providing <=
b>F(Args&&...)</b> is a valid expression, no matter whether F is =
=E2=80=9C<b>CopyConstructible</b>=E2=80=9D.<br></font></div><div><font face=
=3D"georgia, serif" size=3D"2"><br></font></div><div><font face=3D"georgia,=
serif" size=3D"2">An interface may inherit from any number of other interf=
aces providing every expression is <b>unique</b>, e.g.:<br></font></div><di=
v><font face=3D"georgia, serif" size=3D"2"><br></font></div><div><font face=
=3D"georgia, serif" size=3D"2"><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">interface BasicLockable {</div><div class=3D"=
subprettyprint">=C2=A0 void lock();</div><div class=3D"subprettyprint">=C2=
=A0 void unlock();</div><div class=3D"subprettyprint">};<br><br></div><div =
class=3D"subprettyprint">interface Lockable : BasicLockable {</div><div cla=
ss=3D"subprettyprint">=C2=A0 bool try_lock();</div><div class=3D"subprettyp=
rint">};</div></div></code></div><br>are valid expressions, while:<br></fon=
t></div><div><font face=3D"georgia, serif" size=3D"2"><br></font></div><div=
><font size=3D"2"><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">interface A {</div><div class=3D=
"subprettyprint">=C2=A0 void f();</div><div class=3D"subprettyprint">};</di=
v><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">int=
erface B {</div><div class=3D"subprettyprint">=C2=A0 void f();</div><div cl=
ass=3D"subprettyprint">};</div><div class=3D"subprettyprint"><br></div><div=
class=3D"subprettyprint">interface C : A, B {};</div></font></div></code><=
/div><font face=3D"georgia, serif"><br>are invalid expressions.<br></font><=
/font></div><div><font size=3D"2"><font face=3D"georgia, serif"><br></font>=
</font></div><div><font face=3D"georgia, serif"><div><font size=3D"6">Possi=
ble implementation</font></div><div style=3D"font-size: small;"><br></div><=
/font></div><div><font face=3D"georgia, serif" size=3D"2">In C++, the use o=
f polymorphism is usually accompanied by pointers and virtual member functi=
ons. In most cases, raw pointers are the last things we want to program wit=
h, because pointers can have polymorphism mechanism and may increase the ri=
sk of memory leak. That is probably the main reason why =E2=80=9C<b>std::un=
ique_ptr</b>=E2=80=9D and =E2=80=9C<b>std::shared_ptr</b>=E2=80=9D are intr=
oduced in the standard.<br></font></div><div><font face=3D"georgia, serif">=
<br></font></div><div><font face=3D"georgia, serif" size=3D"2">This feature=
requires compiler support in parsing and code generation. Complier may imp=
lement the feature with =E2=80=9C<b>std::unique_ptr</b>=E2=80=9D if it is u=
nnecessary to be =E2=80=9C<b>CopyConstructible</b>=E2=80=9D, or with =E2=80=
=9C<b>std::shared_ptr</b>=E2=80=9D otherwise.<br></font></div><div><font fa=
ce=3D"georgia, serif" size=3D"2"><br></font></div><div><font face=3D"georgi=
a, serif" size=3D"2">For the =E2=80=9C<b>Runnable</b>=E2=80=9D interface us=
ed in a threadpool implementation, the following code with=C2=A0=E2=80=9C<b=
>std::unique_ptr</b>=E2=80=9D</font><span style=3D"font-family: georgia, se=
rif; font-size: small;">=C2=A0may be generated automatically (providing=C2=
=A0</span><b style=3D"font-family: georgia, serif; font-size: small;">Conce=
pts TS</b><span style=3D"font-family: georgia, serif; font-size: small;">=
=C2=A0is supported</span><span style=3D"font-family: georgia, serif; font-s=
ize: small;">):</span></div><div><font face=3D"georgia, serif" size=3D"2"><=
br></font></div><div><font size=3D"2"><div class=3D"prettyprint" style=3D"b=
order: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-colo=
r: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subpretty=
print"><font color=3D"#660066"><div class=3D"subprettyprint">class Runnable=
{</div><div class=3D"subprettyprint">=C2=A0public:</div><div class=3D"subp=
rettyprint">=C2=A0 template <class Data></div><div class=3D"subpretty=
print">=C2=A0 Runnable(Data data) requires</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 =C2=A0 requires(Data data) { { data() }; }</div><div class=
=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 : data_(new Implementation<Data=
>(std::move(data))) {}</div><div class=3D"subprettyprint">=C2=A0 Runnabl=
e() =3D default;</div><div class=3D"subprettyprint">=C2=A0 Runnable(Runnabl=
e&&) =3D default;</div><div class=3D"subprettyprint">=C2=A0 Runnabl=
e(const Runnable&) =3D delete;</div><div class=3D"subprettyprint">=C2=
=A0 Runnable& operator=3D(Runnable&&) =3D default;</div><div cl=
ass=3D"subprettyprint">=C2=A0 Runnable& operator=3D(const Runnable&=
) =3D delete;</div><div class=3D"subprettyprint"><br></div><div class=3D"su=
bprettyprint">=C2=A0 void operator()() { data_->op_0(); }</div><div clas=
s=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0private:=
</div><div class=3D"subprettyprint">=C2=A0 class Abstraction {</div><div cl=
ass=3D"subprettyprint">=C2=A0 =C2=A0public:</div><div class=3D"subprettypri=
nt">=C2=A0 =C2=A0 virtual void op_0() =3D 0;</div><div class=3D"subprettypr=
int">=C2=A0 =C2=A0 virtual ~Abstraction() {}</div><div class=3D"subprettypr=
int">=C2=A0 };</div><div class=3D"subprettyprint"><br></div><div class=3D"s=
ubprettyprint">=C2=A0 template <class Data></div><div class=3D"subpre=
ttyprint">=C2=A0 class Implementation final : public Abstraction {</div><di=
v class=3D"subprettyprint">=C2=A0 =C2=A0public:</div><div class=3D"subprett=
yprint">=C2=A0 =C2=A0 Implementation(Data&& data) : data_(std::forw=
ard<Data>(data)) {}</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
void op_0() override { 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 };</div><div class=3D"subprettyprint"><br></div><div class=3D"subp=
rettyprint">=C2=A0 std::unique_ptr<Abstraction> data_;</div><div clas=
s=3D"subprettyprint">};</div></font></div></code></div><font face=3D"georgi=
a, serif"><br>Whose class diagram is as follows:<br></font></font></div><di=
v><font size=3D"2"><font face=3D"georgia, serif"><br></font></font></div><p=
class=3D"separator" style=3D"text-align: center; clear: both;"><a imageanc=
hor=3D"1" href=3D"https://lh3.googleusercontent.com/-nCZsS4sj_68/WQ_-f0SSzC=
I/AAAAAAAAADA/XienHN-D9qMeRCBFPRSDxX3lFc9GJM7QgCLcB/s1600/123.png" style=3D=
"margin-left: 1em; margin-right: 1em;"><img src=3D"https://lh3.googleuserco=
ntent.com/-nCZsS4sj_68/WQ_-f0SSzCI/AAAAAAAAADA/XienHN-D9qMeRCBFPRSDxX3lFc9G=
JM7QgCLcB/s400/123.png" border=3D"0" width=3D"400" height=3D"133"></a></p><=
div><font size=3D"2"><font face=3D"georgia, serif"><br></font></font></div>=
<div><font face=3D"georgia, serif" size=3D"2">For <b>callable </b>types tha=
t are required to be =E2=80=9C<b>CopyConstructible</b>=E2=80=9D, the follow=
ing code with=C2=A0=E2=80=9C<b>std::shared_ptr</b>=E2=80=9D</font><span sty=
le=3D"font-family: georgia, serif; font-size: small;">=C2=A0may be generate=
d automatically:</span></div><div><font face=3D"georgia, serif" size=3D"2">=
<br></font></div><div><font size=3D"2"><div class=3D"prettyprint" style=3D"=
border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-col=
or: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprett=
yprint"><font color=3D"#660066"><div class=3D"subprettyprint">template <=
class R, class... Args></div><div class=3D"subprettyprint">class Callabl=
e {</div><div class=3D"subprettyprint">=C2=A0public:</div><div class=3D"sub=
prettyprint">=C2=A0 template <class Data></div><div class=3D"subprett=
yprint">=C2=A0 Callable(Data data) requires</div><div class=3D"subprettypri=
nt">=C2=A0 =C2=A0 =C2=A0 requires(Data data, Args... args) { { data(std::mo=
ve(args)...) } -> R; }</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
=C2=A0 : data_(new Implementation<Data>(std::move(data))) {}</div><di=
v class=3D"subprettyprint">=C2=A0 Callable() =3D default;</div><div class=
=3D"subprettyprint">=C2=A0 Callable(Callable&&) =3D default;</div><=
div class=3D"subprettyprint">=C2=A0 Callable(const Callable&) =3D defau=
lt;</div><div class=3D"subprettyprint">=C2=A0 Callable& operator=3D(Cal=
lable&&) =3D default;</div><div class=3D"subprettyprint">=C2=A0 Cal=
lable& operator=3D(const Callable&) =3D default;</div><div class=3D=
"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 void operat=
or()(Args... args) { data_->op_0(std::move(args)...); }</div><div class=
=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0private:<=
/div><div class=3D"subprettyprint">=C2=A0 class Abstraction {</div><div cla=
ss=3D"subprettyprint">=C2=A0 =C2=A0public:</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 virtual void op_0(Args&&...) =3D 0;</div><div clas=
s=3D"subprettyprint">=C2=A0 =C2=A0 virtual ~Abstraction() {}</div><div clas=
s=3D"subprettyprint">=C2=A0 };</div><div class=3D"subprettyprint"><br></div=
><div class=3D"subprettyprint">=C2=A0 template <class Data></div><div=
class=3D"subprettyprint">=C2=A0 class Implementation final : public Abstra=
ction {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0public:</div><div c=
lass=3D"subprettyprint">=C2=A0 =C2=A0 Implementation(Data&& data) :=
data_(std::forward<Data>(data)) {}</div><div class=3D"subprettyprint=
">=C2=A0 =C2=A0 void op_0(Args&&... args) override { data_(std::for=
ward<Args>(args)...); }</div><div class=3D"subprettyprint"><br></div>=
<div class=3D"subprettyprint">=C2=A0 =C2=A0private:</div><div class=3D"subp=
rettyprint">=C2=A0 =C2=A0 Data data_;</div><div class=3D"subprettyprint">=
=C2=A0 };</div><div class=3D"subprettyprint"><br></div><div class=3D"subpre=
ttyprint">=C2=A0 std::shared_ptr<Abstraction> data_;</div><div class=
=3D"subprettyprint">};</div></font></div></code></div><font face=3D"georgia=
, serif"><br>I am looking forward to your=C2=A0</font></font><font face=3D"=
georgia, serif" size=3D"2">comments and suggestions!</font></div><div><font=
face=3D"georgia, serif" size=3D"2"><br></font></div><div><font face=3D"geo=
rgia, serif" size=3D"2">Thank you.</font></div><div><font face=3D"georgia, =
serif" size=3D"2"><br></font></div><div><font face=3D"georgia, serif" size=
=3D"2">Mingxin Wang</font></div><div><font face=3D"georgia, serif" size=3D"=
2"><br></font></div><div><font face=3D"georgia, serif" size=3D"2"><br></fon=
t></div><div><font face=3D"georgia, serif" size=3D"2"><br></font></div><div=
><font face=3D"georgia, serif" size=3D"2"><br></font></div><div><font face=
=3D"georgia, serif" size=3D"2"><br></font></div><div><font face=3D"georgia,=
serif" size=3D"2"><br></font></div><div><font face=3D"georgia, serif" size=
=3D"2"><br></font></div><div><font face=3D"georgia, serif" size=3D"2"><br><=
/font></div><div><font face=3D"georgia, serif" size=3D"2"><br></font></div>=
<div><font face=3D"georgia, serif" size=3D"2"><br></font></div><div><font f=
ace=3D"georgia, serif" size=3D"2"><br></font></div><div><font face=3D"georg=
ia, serif" size=3D"2"><br></font></div><div><font face=3D"georgia, serif" s=
ize=3D"2"><br></font></div><div><font face=3D"georgia, serif" size=3D"2"><b=
r></font></div><div><font face=3D"georgia, serif" size=3D"2">.</font></div>=
</div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/c8742174-fef0-44a9-988d-2c8aebba9243%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/c8742174-fef0-44a9-988d-2c8aebba9243=
%40isocpp.org</a>.<br />
------=_Part_1492_1896983442.1494220992771--
------=_Part_1491_1554325809.1494220992770--
.