Topic: The Polymorphic Pointers - A Feature Decoupling
Author: Mingxin Wang <wmx16835vv@163.com>
Date: Mon, 26 Jun 2017 05:43:50 -0700 (PDT)
Raw View
------=_Part_1580_1230667838.1498481030962
Content-Type: multipart/alternative;
boundary="----=_Part_1581_148286827.1498481030963"
------=_Part_1581_148286827.1498481030963
Content-Type: text/plain; charset="UTF-8"
*Introduction*
This thread is an update version for "The Proxies - A Language Feature
Decoupling Implementations from Requirements of Polymorphism
<https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/lfAr1ef22YM>",
"Adding the Keyword "proxy" in C++
<https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/kvkgsHM6wFQ>"
and "Adding the Keyword "interface" in C++
<https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/uyfpeyEyW4o>
".
After careful consideration, I found it was not elegant enough to solve the
"polymorphism" issue with the magic class template "proxy", because there
are actually two duck-typing requirements in this issue: the first is to
implement the specified interface (aka. pure virtual class) for each
possible type, which is exactly what the solution aims to solve; and the
second is to forward the operations to the type-specific implementations
with non-virtual member functions, which has nothing to do with
polymorphism, and is only syntactical duck-typing.
In this solution, the two duck-typing requirements are decoupled from each
other, so that the feature has simpler and more explicit semantics. The new
feature is called the "polymorphic pointers" (provisionally).
*Technical Specifications*
*Wrapper requirements (Remain unchanged)*
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 type-erased pointer of the wrapped object.
*Class template poly_ptr*
Like std::unique_ptr, std::shared_ptr and raw pointers, the poly_ptr class
template has pointer semantics. A poly_ptr shall be specified by two types,
the first shall be a well-formed pure virtual class type, and the second
shall meet the Wrapper requirements.
A poly_ptr has similar properties as the specified Wrapper type does,
including CopyConstructible, MoveConstructible, DefaultConstructible,
CopyAssignable, MoveAssignable, etc. A poly_ptr is able to be converted
from a type iff the specified Wrapper type is able to be converted from the
type. The following code shows possible (key) synopsis for poly_ptr. More
work is still required to make it detailed.
template <class I, class W>
class poly_ptr; // undefined
template <class I, class W> requires requires(W w) { { w.get() } -> void*; }
class poly_ptr {
public:
poly_ptr() requires std::experimental::ranges::DefaultConstructible<W>();
template <class T>
poly_ptr(T&&) requires
!std::is_same<std::remove_cv_t<std::remove_reference_t<T>>,
poly_ptr>::value && std::experimental::ranges::Constructible<W, T&&>();
poly_ptr(poly_ptr&&) requires
std::experimental::ranges::MoveConstructible<W>();
poly_ptr(const poly_ptr&) requires
std::experimental::ranges::CopyConstructible<W>();
template <class T>
poly_ptr& operator=(T&&) requires
!std::is_same<std::remove_cv_t<std::remove_reference_t<T>>,
poly_ptr>::value && std::experimental::ranges::Constructible<W, T&&>();
poly_ptr& operator=(poly_ptr&&) requires
std::experimental::ranges::MoveConstructible<W>();
poly_ptr& operator=(const poly_ptr&) requires
std::experimental::ranges::CopyConstructible<W>();
~poly_ptr();
I* get();
const I* get() const;
I& operator*();
const I& operator*() const;
I* operator->();
const I* operator->() const;
};
*Observers*
Still working on it...
*Prototypes for Wrappers (Remain unchanged)*
Class "shared_wrapper" (with shared semantics), class template
"deep_wrapper" (with value semantics and SOO feature), class template
"trivial_wrapper" (with value semantics and designed for trivial types) and
class "deferred_wrapper" (with reference semantics) are designed to meet
the Wrapper requirements. Possible implementation is included in the
attachments (wrappers.cc).
*Aliases*
template <class I> using shared_poly_ptr = poly_ptr<I, shared_wrapper>;
template <class I, std::size_t SOO_SIZE> using deep_poly_ptr = poly_ptr<I,
deep_wrapper<SOO_SIZE>>;
template <class I> using deferred_poly_ptr = poly_ptr<I, deferred_wrapper>;
template <class I, std::size_t SIZE> using trivial_poly_ptr = poly_ptr<I,
trivial_wrapper<SIZE>>;
*Code Generation*
Still 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) = 0;
};
The code that the compiler will possibly generate for the type
"poly_ptr<Callable<R(Args...)>, W>" is as shown below:
#include <system_error>
/* Auto generated specialization for poly_ptr<Callable<R(Args...)>, W> */
/* To make this implementation brief, some concepts are omitted */
template <class R, class... Args, class W> requires Wrapper<W>()
class poly_ptr<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
interface */
template <class T>
poly_ptr(T&& data) requires
!std::is_same<raw_type<T>, poly_ptr>::value &&
requires(T f, Args&&... args) { { f(std::forward<Args>(args)...) } ->
R; }
{ init(std::forward<T>(data)); }
/* Default constructor */
poly_ptr() { init(); }
/* Move constructor */
poly_ptr(poly_ptr&& lhs) { lhs.move_init(*this); }
/* Copy constructor */
poly_ptr(const poly_ptr& rhs) { rhs.copy_init(*this); }
/* Destructor */
~poly_ptr() { deinit(); }
poly_ptr& operator=(const poly_ptr& rhs) {
deinit();
rhs.copy_init(*this);
return *this;
}
poly_ptr& operator=(poly_ptr&& lhs) {
deinit();
lhs.move_init(*this);
return *this;
}
template <class T>
poly_ptr& operator=(T&& data) requires
!std::is_same<raw_type<T>, poly_ptr>::value {
deinit();
init(std::forward<T>(data));
return *this;
}
/* Pointer semantics */
Callable<R(Args...)>* get() { return
reinterpret_cast<Callable<R(Args...)>*>(data_); }
const Callable<R(Args...)>* get() const { return reinterpret_cast<const
Callable<R(Args...)>*>(data_); }
Callable<R(Args...)>& operator*() { return *get(); }
const Callable<R(Args...)>& operator*() const { return *get(); }
Callable<R(Args...)>* operator->() { return get(); }
const Callable<R(Args...)>* operator->() const { return get(); }
private:
/* Base class, extending the original interface */
class Abstraction : public Callable<R(Args...)> {
public:
Abstraction() = 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_)
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 pointer");
}
};
/* 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
(*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
(reinterpret_cast<Implementation<std::remove_reference_t<T>>*>(data_))
Implementation<std::remove_reference_t<T>>(std::forward<T>(data));
}
/* Copy semantics */
void copy_init(poly_ptr& rhs) const {
// Forward this operation
reinterpret_cast<const Abstraction*>(data_)->copy_init(rhs.data_);
}
/* Move semantics */
void move_init(poly_ptr& rhs) {
// Forward this operation
reinterpret_cast<Abstraction*>(data_)->move_init(rhs.data_);
}
/* Destroy semantics */
void deinit() {
// Forward this operation
reinterpret_cast<Abstraction*>(data_)->~Abstraction();
}
char data_[sizeof(Uninitialized)];
};
*Comparing to the Last Solution (The Proxies)*
In the last solution, the proxy is required to define non-virtual member
functions and forward any parameter when calling some virtual member
function defined in the specified pure virtual class. For example,
providing there is a pure virtual class defined as below:
class InterfaceDemo {
public:
virtual int f(int, double) = 0;
virtual void g(int = 3) = 0;
};
The following expressions shall be well-formed if W meets the wrapper
requirements:
proxy<InterfaceDemo, W> p { /* Initialize */ };
p.f(1, 2.0); // Calling InterfaceDemo::f(int, double)
p.f(3, 4); // Calling InterfaceDemo::f(int, int)
p.g(5); // Calling InterfaceDemo::g(int)
p.g(); // Calling InterfaceDemo::g()
Thus the member functions defined in proxy<InterfaceDemo, W> shall be able
to *accept any legal combination of types*, as is shown below (exposition
only):
template <class W> requires Wrapper<W>()
class proxy<InterfaceDemo, W> {
public:
/* ... */
template <class... Args>
int f(Args&&... args) { return get_ptr()->f(std::forward<Args>(args)...);
}
template <class... Args>
int g(Args&&... args) { return get_ptr()->g(std::forward<Args>(args)...);
}
/* ... */
private:
InterfaceDemo* get_ptr();
};
From which, users (and other IDE plugins) are not able to directly infer
the original signature of f and g. While in this solution, poly_ptr<I, W>
can be regarded as an ordinary pointer equivalent to I*.
Accompanied with the explicitness of semantics, if we want to use a
poly_ptr (as well as std::unique_ptr, std::shared_ptr and raw pointers) as
a value, it is required to define the proxy types manually as we used to do
(or maybe introduce such language feature in the standard, but that is
another story). Take the callable interface as an example, we can define
the following type that converts pointer semantics to value semantics:
template <class P>
class callable_proxy {
public:
template <class... Args>
callable_proxy(Args&&... args) requires
(sizeof...(Args) != 1u ||
!std::is_same<raw_type<std::tuple_element_t<0, std::tuple<Args...>>>,
callable_proxy>::value)
: p_(std::forward<Args>(args)...) {}
callable_proxy(const callable_proxy&) = default;
callable_proxy(callable_proxy&&) = default;
template <class... Args>
auto operator()(Args&&... args) { return
(*p_)(std::forward<Args>(args)...); }
private:
P p_;
};
Then, callable_proxy<deep_poly_ptr<Callable<void()>, 16u>> is equivalent to
deep_proxy<Callable<void()>, 16u> in the last solution, whose performance
has already been compared with the implementation of std::function<void()>
we have in GCC.
I am looking forward to your comments and suggestions!
Thank you!
Mingxin Wang
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e9edecb7-14dc-4cf4-8dcd-4f376de01137%40isocpp.org.
------=_Part_1581_148286827.1498481030963
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><b><font size=3D"6">Introduction</font></b></div><div=
><br></div><div>This thread is an update version for "<a href=3D"https=
://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/lfAr1ef22YM">=
The Proxies - A Language Feature Decoupling Implementations from Requiremen=
ts of Polymorphism</a>", "<a href=3D"https://groups.google.com/a/=
isocpp.org/forum/#!topic/std-proposals/kvkgsHM6wFQ">Adding the Keyword &quo=
t;proxy" in C++</a>" and "<a href=3D"https://groups.google.c=
om/a/isocpp.org/forum/#!topic/std-proposals/uyfpeyEyW4o">Adding the Keyword=
"interface" in C++</a>".</div><div><br></div><div>After car=
eful consideration, I found it was not elegant enough to solve the "po=
lymorphism" issue with the magic class template "proxy", bec=
ause there are actually two duck-typing requirements in this issue: the fir=
st is to implement the specified interface (aka. pure virtual class) for ea=
ch possible type, which is exactly what the solution aims to solve; and the=
second is to forward the operations to the type-specific implementations w=
ith non-virtual member functions, which has nothing to do with polymorphism=
, and is only syntactical duck-typing.</div><div><br></div><div>In this sol=
ution, the two duck-typing requirements are decoupled from each other, so t=
hat=C2=A0the feature has simpler and more explicit semantics. The new featu=
re is called the "polymorphic pointers" (provisionally).</div><di=
v><br></div><div><b><font size=3D"6">Technical Specifications</font></b><br=
></div><div><br></div><div><div><font size=3D"4"><b>Wrapper requirements (R=
emain unchanged)</b></font></div><div><br></div><div>A type W meets the Wra=
pper requirements if the following expressions are well-formed and have the=
specific 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 of the wrapped object if there is one.</div><div><span class=3D"Ap=
ple-tab-span" style=3D"white-space:pre"> </span>Return type: void*.</div><d=
iv><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>Returns=
: a type-erased pointer of the wrapped object.</div></div><div><br></div><d=
iv><font size=3D"4"><b>Class template poly_ptr</b></font></div><div><br></d=
iv><div><div>Like std::unique_ptr, std::shared_ptr and raw pointers, the po=
ly_ptr class template has pointer semantics. A poly_ptr shall be specified =
by two types, the first shall be a well-formed pure virtual class type, and=
the second shall meet the Wrapper requirements.</div><div><br></div><div>A=
poly_ptr has similar properties as the specified Wrapper type does, includ=
ing CopyConstructible, MoveConstructible, DefaultConstructible, CopyAssigna=
ble, MoveAssignable, etc. A poly_ptr is able to be converted from a type if=
f the specified Wrapper type is able to be converted from the type. The fol=
lowing code shows=C2=A0possible (key) synopsis for poly_ptr. More work is s=
till required to make it detailed.</div></div><div><br></div><div><div clas=
s=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap:=
break-word; background-color: rgb(250, 250, 250);"><code class=3D"prettypr=
int"><div class=3D"subprettyprint"><font color=3D"#660066"><div class=3D"su=
bprettyprint"><div class=3D"subprettyprint">template <class I, class W&g=
t;</div><div class=3D"subprettyprint">class poly_ptr; // undefined</div><di=
v class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">template=
<class I, class W> requires requires(W w) { { w.get() } -> void*;=
}</div><div class=3D"subprettyprint">class poly_ptr {</div><div class=3D"s=
ubprettyprint">=C2=A0public:</div><div class=3D"subprettyprint">=C2=A0 poly=
_ptr() requires std::experimental::ranges::DefaultConstructible<W>();=
</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint"=
>=C2=A0 template <class T></div><div class=3D"subprettyprint">=C2=A0 =
poly_ptr(T&&) requires !std::is_same<std::remove_cv_t<std::re=
move_reference_t<T>>, poly_ptr>::value && std::experime=
ntal::ranges::Constructible<W, T&&>();</div><div class=3D"sub=
prettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 poly_ptr(poly_p=
tr&&) requires std::experimental::ranges::MoveConstructible<W>=
;();</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettypr=
int">=C2=A0 poly_ptr(const poly_ptr&) requires std::experimental::range=
s::CopyConstructible<W>();</div><div class=3D"subprettyprint"><br></d=
iv><div class=3D"subprettyprint">=C2=A0 template <class T></div><div =
class=3D"subprettyprint">=C2=A0 poly_ptr& operator=3D(T&&) requ=
ires !std::is_same<std::remove_cv_t<std::remove_reference_t<T>&=
gt;, poly_ptr>::value && std::experimental::ranges::Constructibl=
e<W, T&&>();</div><div class=3D"subprettyprint"><br></div><di=
v class=3D"subprettyprint">=C2=A0 poly_ptr& operator=3D(poly_ptr&&a=
mp;) requires std::experimental::ranges::MoveConstructible<W>();</div=
><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=
=A0 poly_ptr& operator=3D(const poly_ptr&) requires std::experiment=
al::ranges::CopyConstructible<W>();</div><div class=3D"subprettyprint=
"><br></div><div class=3D"subprettyprint">=C2=A0 ~poly_ptr();</div><div cla=
ss=3D"subprettyprint">=C2=A0=C2=A0</div><div class=3D"subprettyprint">=C2=
=A0 I* get();</div><div class=3D"subprettyprint">=C2=A0 const I* get() cons=
t;</div><div class=3D"subprettyprint">=C2=A0 I& operator*();</div><div =
class=3D"subprettyprint">=C2=A0 const I& operator*() const;</div><div c=
lass=3D"subprettyprint">=C2=A0 I* operator->();</div><div class=3D"subpr=
ettyprint">=C2=A0 const I* operator->() const;</div><div class=3D"subpre=
ttyprint">};</div></div></font></div></code></div><br></div><div><b><font s=
ize=3D"4">Observers</font></b></div><div><br></div><div>Still working on it=
....</div><div><br></div><div><b><font size=3D"4">Prototypes for Wrappers (R=
emain unchanged)</font></b><br></div><div><br></div><div>Class "shared=
_wrapper" (with shared semantics), class template "deep_wrapper&q=
uot; (with value semantics and SOO feature), class template "trivial_w=
rapper" (with value semantics and designed for trivial types) and clas=
s "deferred_wrapper" (with reference semantics) are designed to m=
eet the Wrapper requirements. Possible implementation is included in the at=
tachments (wrappers.cc).<br></div><div><br></div><div><b><font size=3D"4">A=
liases</font></b><br></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"><div class=3D"subprettyprint">template <class I> usin=
g shared_poly_ptr =3D poly_ptr<I, shared_wrapper>;</div><div class=3D=
"subprettyprint">template <class I, std::size_t SOO_SIZE> using deep_=
poly_ptr =3D poly_ptr<I, deep_wrapper<SOO_SIZE>>;</div><div cla=
ss=3D"subprettyprint">template <class I> using deferred_poly_ptr =3D =
poly_ptr<I, deferred_wrapper>;</div><div class=3D"subprettyprint">tem=
plate <class I, std::size_t SIZE> using trivial_poly_ptr =3D poly_ptr=
<I, trivial_wrapper<SIZE>>;</div></div></code></div><br></div><=
div><font size=3D"6"><b>Code Generation</b></font></div><div><br></div><div=
>Still take the "Callable" interface as an example:<br></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 <class T></div><div c=
lass=3D"subprettyprint">class Callable; // undefined</div><div class=3D"sub=
prettyprint"><br></div><div class=3D"subprettyprint">/* Interface declarati=
on with pure virtual class */</div><div class=3D"subprettyprint">template &=
lt;class R, class... Args></div><div class=3D"subprettyprint">class Call=
able<R(Args...)> {</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></di=
v><br>The code that the compiler will possibly generate for the type "=
poly_ptr<Callable<R(Args...)>, W>" is as shown below:<br><=
/div><div><br></div><div><div class=3D"prettyprint" style=3D"border: 1px so=
lid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb(250, 2=
50, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"><font =
color=3D"#660066"><div class=3D"subprettyprint">#include <system_error&g=
t;</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprin=
t">/* Auto generated specialization for poly_ptr<Callable<R(Args...)&=
gt;, W> */</div><div class=3D"subprettyprint">/* To make this implementa=
tion brief, some concepts are omitted */</div><div class=3D"subprettyprint"=
>template <class R, class... Args, class W> requires Wrapper<W>=
()</div><div class=3D"subprettyprint">class poly_ptr<Callable<R(Args.=
...)>, W> {</div><div class=3D"subprettyprint">=C2=A0public:</div><div=
class=3D"subprettyprint">=C2=A0 /* Construct with a value of any type */</=
div><div class=3D"subprettyprint">=C2=A0 /* More concepts may be required t=
o check whether T is suitable for this interface */</div><div class=3D"subp=
rettyprint">=C2=A0 template <class T></div><div class=3D"subprettypri=
nt">=C2=A0 poly_ptr(T&& data) requires</div><div class=3D"subpretty=
print">=C2=A0 =C2=A0 =C2=A0 !std::is_same<raw_type<T>, poly_ptr>=
;::value &&</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0=
requires(T f, Args&&... args) { { f(std::forward<Args>(args)=
....) } -> R; }</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 {=
init(std::forward<T>(data)); }</div><div class=3D"subprettyprint"><b=
r></div><div class=3D"subprettyprint">=C2=A0 /* Default constructor */</div=
><div class=3D"subprettyprint">=C2=A0 poly_ptr() { init(); }</div><div clas=
s=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Move=
constructor */</div><div class=3D"subprettyprint">=C2=A0 poly_ptr(poly_ptr=
&& lhs) { lhs.move_init(*this); }</div><div class=3D"subprettyprint=
"><br></div><div class=3D"subprettyprint">=C2=A0 /* Copy constructor */</di=
v><div class=3D"subprettyprint">=C2=A0 poly_ptr(const poly_ptr& rhs) { =
rhs.copy_init(*this); }</div><div class=3D"subprettyprint"><br></div><div c=
lass=3D"subprettyprint">=C2=A0 /* Destructor */</div><div class=3D"subprett=
yprint">=C2=A0 ~poly_ptr() { deinit(); }</div><div class=3D"subprettyprint"=
><br></div><div class=3D"subprettyprint">=C2=A0 poly_ptr& operator=3D(c=
onst poly_ptr& rhs) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
deinit();</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 rhs.copy_init(*t=
his);</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return *this;</div><=
div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><b=
r></div><div class=3D"subprettyprint">=C2=A0 poly_ptr& operator=3D(poly=
_ptr&& lhs) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 dein=
it();</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 lhs.move_init(*this)=
;</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 return *this;</div><div =
class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br></=
div><div class=3D"subprettyprint">=C2=A0 template <class T></div><div=
class=3D"subprettyprint">=C2=A0 poly_ptr& operator=3D(T&& data=
) requires</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 !std::is=
_same<raw_type<T>, poly_ptr>::value {</div><div class=3D"subpre=
ttyprint">=C2=A0 =C2=A0 deinit();</div><div class=3D"subprettyprint">=C2=A0=
=C2=A0 init(std::forward<T>(data));</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 return *this;</div><div class=3D"subprettyprint">=C2=A0 }<=
/div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=
=C2=A0 /* Pointer semantics */</div><div class=3D"subprettyprint">=C2=A0 Ca=
llable<R(Args...)>* get() { return reinterpret_cast<Callable<R(=
Args...)>*>(data_); }</div><div class=3D"subprettyprint">=C2=A0 const=
Callable<R(Args...)>* get() const { return reinterpret_cast<const=
Callable<R(Args...)>*>(data_); }</div><div class=3D"subprettyprin=
t">=C2=A0 Callable<R(Args...)>& operator*() { return *get(); }</d=
iv><div class=3D"subprettyprint">=C2=A0 const Callable<R(Args...)>&am=
p; operator*() const { return *get(); }</div><div class=3D"subprettyprint">=
=C2=A0 Callable<R(Args...)>* operator->() { return get(); }</div><=
div class=3D"subprettyprint">=C2=A0 const Callable<R(Args...)>* opera=
tor->() const { return get(); }</div><div class=3D"subprettyprint"><br><=
/div><div class=3D"subprettyprint">=C2=A0private:</div><div class=3D"subpre=
ttyprint">=C2=A0 /* Base class, extending the original interface */</div><d=
iv class=3D"subprettyprint">=C2=A0 class Abstraction : public Callable<R=
(Args...)> {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0public:</di=
v><div class=3D"subprettyprint">=C2=A0 =C2=A0 Abstraction() =3D default;</d=
iv><div class=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=
=C2=A0 =C2=A0 /* Initialize the wrapper */</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 template <class T></div><div class=3D"subprettyprint=
">=C2=A0 =C2=A0 Abstraction(T&& data) : wrapper_(std::forward<T&=
gt;(data)) {}</div><div class=3D"subprettyprint"><br></div><div class=3D"su=
bprettyprint">=C2=A0 =C2=A0 /* Non-virtual copy construct */</div><div clas=
s=3D"subprettyprint">=C2=A0 =C2=A0 void copy_init(void* mem) const {</div><=
div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 /* Copy the pointer of th=
e vtable */</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 memcpy(=
mem, this, sizeof(Callable<R(Args...)>));</div><div class=3D"subprett=
yprint"><br></div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 /* Ini=
tialize the wrapper with lvalue */</div><div class=3D"subprettyprint">=C2=
=A0 =C2=A0 =C2=A0 new (&reinterpret_cast<Abstraction*>(mem)->w=
rapper_) W(wrapper_);</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 }</d=
iv><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<R(Args...)>)=
);</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 new (&reinte=
rpret_cast<Abstraction*>(mem)->wrapper_) W(std::move(wrapper_));</=
div><div class=3D"subprettyprint">=C2=A0 =C2=A0 }</div><div class=3D"subpre=
ttyprint"><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"subp=
rettyprint">=C2=A0 class Uninitialized : public Abstraction {</div><div cla=
ss=3D"subprettyprint">=C2=A0 =C2=A0public:</div><div class=3D"subprettyprin=
t">=C2=A0 =C2=A0 /* Only for demonstration */</div><div class=3D"subprettyp=
rint">=C2=A0 =C2=A0 R operator()(Args...) override {</div><div class=3D"sub=
prettyprint">=C2=A0 =C2=A0 =C2=A0 throw std::runtime_error("Using unin=
itialized pointer");</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =
}</div><div class=3D"subprettyprint">=C2=A0 };</div><div class=3D"subpretty=
print"><br></div><div class=3D"subprettyprint">=C2=A0 /* Type-specific impl=
ementation */</div><div class=3D"subprettyprint">=C2=A0 template <class =
T></div><div class=3D"subprettyprint">=C2=A0 class Implementation : publ=
ic Abstraction {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0public:</d=
iv><div class=3D"subprettyprint">=C2=A0 =C2=A0 template <class U></di=
v><div class=3D"subprettyprint">=C2=A0 =C2=A0 Implementation(U&& da=
ta) : Abstraction(std::forward<U>(data)) {}</div><div class=3D"subpre=
ttyprint"><br></div><div class=3D"subprettyprint">=C2=A0 =C2=A0 R operator(=
)(Args... 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<T*>=
;(this->wrapper_.get()))(std::forward<Args>(args)...);</div><div c=
lass=3D"subprettyprint">=C2=A0 =C2=A0 }</div><div class=3D"subprettyprint">=
=C2=A0 };</div><div class=3D"subprettyprint"><br></div><div class=3D"subpre=
ttyprint">=C2=A0 void init() {</div><div class=3D"subprettyprint">=C2=A0 =
=C2=A0 new (reinterpret_cast<Uninitialized*>(data_.get())) Uninitiali=
zed();</div><div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subpr=
ettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Initialize wit=
h a concrete type and value */</div><div class=3D"subprettyprint">=C2=A0 te=
mplate <class T></div><div class=3D"subprettyprint">=C2=A0 void init(=
T&& data) {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 new (r=
einterpret_cast<Implementation<std::remove_reference_t<T>>*&=
gt;(data_))</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
Implementation<std::remove_reference_t<T>>(std::forward<T>=
;(data));</div><div class=3D"subprettyprint">=C2=A0 }</div><div class=3D"su=
bprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 /* Copy semant=
ics */</div><div class=3D"subprettyprint">=C2=A0 void copy_init(poly_ptr&am=
p; rhs) const {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // Forward=
this operation</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 reinterpre=
t_cast<const Abstraction*>(data_)->copy_init(rhs.data_);</div><div=
class=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br><=
/div><div class=3D"subprettyprint">=C2=A0 /* Move semantics */</div><div cl=
ass=3D"subprettyprint">=C2=A0 void move_init(poly_ptr& rhs) {</div><div=
class=3D"subprettyprint">=C2=A0 =C2=A0 // Forward this operation</div><div=
class=3D"subprettyprint">=C2=A0 =C2=A0 reinterpret_cast<Abstraction*>=
;(data_)->move_init(rhs.data_);</div><div class=3D"subprettyprint">=C2=
=A0 }</div><div class=3D"subprettyprint"><br></div><div class=3D"subprettyp=
rint">=C2=A0 /* Destroy semantics */</div><div class=3D"subprettyprint">=C2=
=A0 void deinit() {</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 // For=
ward this operation</div><div class=3D"subprettyprint">=C2=A0 =C2=A0 reinte=
rpret_cast<Abstraction*>(data_)->~Abstraction();</div><div class=
=3D"subprettyprint">=C2=A0 }</div><div class=3D"subprettyprint"><br></div><=
div class=3D"subprettyprint">=C2=A0 char data_[sizeof(Uninitialized)];</div=
><div class=3D"subprettyprint">};</div></font></div></code></div></div><div=
><br></div><div><b><font size=3D"6">Comparing to the Last Solution (The Pro=
xies)</font></b></div><div><br></div><div>In the last solution, the proxy i=
s required to define non-virtual member functions and forward any parameter=
when calling some virtual member function defined in the specified pure vi=
rtual class. For example, providing there is a pure virtual class defined a=
s below:</div><div><br></div><div><div class=3D"prettyprint" style=3D"borde=
r: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-color: r=
gb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprin=
t"><div class=3D"subprettyprint">class InterfaceDemo {</div><div class=3D"s=
ubprettyprint">=C2=A0public:</div><div class=3D"subprettyprint">=C2=A0 virt=
ual int f(int, double) =3D 0;</div><div class=3D"subprettyprint">=C2=A0 vir=
tual void g(int =3D 3) =3D 0;</div><div class=3D"subprettyprint">};</div></=
div></code></div><br>The following expressions shall be well-formed if W me=
ets the wrapper requirements:</div><div><br></div><div><div class=3D"pretty=
print" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word=
; background-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div c=
lass=3D"subprettyprint"><div class=3D"subprettyprint">proxy<InterfaceDem=
o, W> p { /* Initialize */ };</div><div class=3D"subprettyprint">p.f(1, =
2.0); // Calling InterfaceDemo::f(int, double)</div><div class=3D"subpretty=
print">p.f(3, 4); // Calling InterfaceDemo::f(int, int)</div><div class=3D"=
subprettyprint">p.g(5); // Calling InterfaceDemo::g(int)</div><div class=3D=
"subprettyprint">p.g(); // Calling InterfaceDemo::g()</div></div></code></d=
iv><br>Thus the member functions defined in proxy<InterfaceDemo, W> s=
hall be able to <i>accept any legal combination of=C2=A0types</i>, as is sh=
own below (exposition only):</div><div><br></div><div><div class=3D"prettyp=
rint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word;=
background-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div cl=
ass=3D"subprettyprint"><div class=3D"subprettyprint">template <class W&g=
t; requires Wrapper<W>()</div><div class=3D"subprettyprint">class pro=
xy<InterfaceDemo, W> {</div><div class=3D"subprettyprint">=C2=A0publi=
c:</div><div class=3D"subprettyprint">=C2=A0 /* ... */</div><div class=3D"s=
ubprettyprint">=C2=A0=C2=A0</div><div class=3D"subprettyprint">=C2=A0 templ=
ate <class... Args></div><div class=3D"subprettyprint">=C2=A0 int f(A=
rgs&&... args) { return get_ptr()->f(std::forward<Args>(ar=
gs)...); }</div><div class=3D"subprettyprint">=C2=A0=C2=A0</div><div class=
=3D"subprettyprint">=C2=A0 template <class... Args></div><div class=
=3D"subprettyprint">=C2=A0 int g(Args&&... args) { return get_ptr()=
->g(std::forward<Args>(args)...); }</div><div class=3D"subprettypr=
int">=C2=A0=C2=A0</div><div class=3D"subprettyprint">=C2=A0 /* ... */</div>=
<div class=3D"subprettyprint">=C2=A0=C2=A0</div><div class=3D"subprettyprin=
t">=C2=A0private:</div><div class=3D"subprettyprint">=C2=A0 InterfaceDemo* =
get_ptr();</div><div class=3D"subprettyprint">};</div></div></code></div></=
div><br><div>From which, users (and other IDE plugins) are not able to dire=
ctly infer the original signature of f and g. While in this solution, poly_=
ptr<I, W> can be regarded as an ordinary pointer equivalent to I*.</d=
iv><div><br></div><div>Accompanied with the explicitness of semantics, if w=
e want to use a poly_ptr (as well as std::unique_ptr, std::shared_ptr and r=
aw pointers) as a value, it is required to define the proxy types manually =
as we used to do (or maybe introduce such language feature in the standard,=
but that is another story). Take the callable interface as an example, we =
can define the following type that converts pointer semantics to value sema=
ntics:</div><div><br></div><div><div class=3D"prettyprint" style=3D"border:=
1px solid rgb(187, 187, 187); word-wrap: break-word; background-color: rgb=
(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprettyprint"=
><font color=3D"#660066"><div class=3D"subprettyprint">template <class P=
></div><div class=3D"subprettyprint">class callable_proxy {</div><div cl=
ass=3D"subprettyprint">=C2=A0public:</div><div class=3D"subprettyprint">=C2=
=A0 template <class... Args></div><div class=3D"subprettyprint">=C2=
=A0 callable_proxy(Args&&... args) requires</div><div class=3D"subp=
rettyprint">=C2=A0 =C2=A0 =C2=A0 (sizeof...(Args) !=3D 1u || !std::is_same&=
lt;raw_type<std::tuple_element_t<0, std::tuple<Args...>>>=
, callable_proxy>::value)</div><div class=3D"subprettyprint">=C2=A0 =C2=
=A0 =C2=A0 : p_(std::forward<Args>(args)...) {}</div><div class=3D"su=
bprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 callable_proxy=
(const callable_proxy&) =3D default;</div><div class=3D"subprettyprint"=
>=C2=A0 callable_proxy(callable_proxy&&) =3D default;</div><div cla=
ss=3D"subprettyprint"><br></div><div class=3D"subprettyprint">=C2=A0 templa=
te <class... Args></div><div class=3D"subprettyprint">=C2=A0 auto ope=
rator()(Args&&... args) { return (*p_)(std::forward<Args>(arg=
s)...); }</div><div class=3D"subprettyprint"><br></div><div class=3D"subpre=
ttyprint">=C2=A0private:</div><div class=3D"subprettyprint">=C2=A0 P p_;</d=
iv><div class=3D"subprettyprint">};</div></font></div></code></div><br>Then=
,=C2=A0callable_proxy<deep_poly_ptr<Callable<void()>, 16u>&g=
t; is equivalent to deep_proxy<Callable<void()>, 16u> in the la=
st solution, whose performance has already been compared with the implement=
ation of std::function<void()> we have in GCC.</div><div><br></div><d=
iv><div>I am looking forward to your comments and suggestions!</div><div><b=
r></div><div>Thank you!</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" 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/e9edecb7-14dc-4cf4-8dcd-4f376de01137%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/e9edecb7-14dc-4cf4-8dcd-4f376de01137=
%40isocpp.org</a>.<br />
------=_Part_1581_148286827.1498481030963--
------=_Part_1580_1230667838.1498481030962
Content-Type: text/x-c++src; charset=US-ASCII; name=wrappers.cc
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=wrappers.cc
X-Attachment-Id: 9f4b435d-5012-48f7-96e8-33db27c4e2ba
Content-ID: <9f4b435d-5012-48f7-96e8-33db27c4e2ba>
#include <utility>
#include <type_traits>
#include <atomic>
#include <memory>
template <class T>
using raw_type = std::remove_cv_t<std::remove_reference_t<T>>;
/* A deep-copy wrapper with SOO feature */
template <std::size_t SOO_SIZE>
class deep_wrapper {
public:
/* Constructors */
template <class T>
deep_wrapper(T&& data) requires
!std::is_same<raw_type<T>, deep_wrapper>::value
{ init(std::forward<T>(data)); }
deep_wrapper() { init(); }
deep_wrapper(const deep_wrapper& rhs) { rhs.copy_init(*this); }
deep_wrapper(deep_wrapper&& lhs) { lhs.move_init(*this); }
/* Destructor */
~deep_wrapper() { deinit(); }
deep_wrapper& operator=(const deep_wrapper& rhs) {
deinit();
rhs.copy_init(*this);
return *this;
}
deep_wrapper& operator=(deep_wrapper&& lhs) {
deinit();
lhs.move_init(*this);
return *this;
}
/* Meets the Wrapper requirements */
void* get() {
// The address of the wrapped object is calculated with a constant offset
return reinterpret_cast<char*>(holder_) + sizeof(AbstractHolder);
}
private:
/* Pure virtual holder with virtual destructor */
class AbstractHolder {
public:
virtual ~AbstractHolder() {}
virtual void copy_init(deep_wrapper&) = 0;
virtual void move_init(deep_wrapper&) = 0;
};
template <class T>
class ConcreteHolder : public AbstractHolder {
public:
/* Constructor */
template <class U>
ConcreteHolder(U&& data) : data_(std::forward<U>(data)) {}
void copy_init(deep_wrapper& rhs) override { rhs.init(data_); }
void move_init(deep_wrapper& rhs) override { rhs.init(std::move(data_)); }
private:
/* Holds the concrete value */
T data_;
};
/* Initialize *this to be invalid */
void init() { holder_ = nullptr; }
/* Overload for small object */
template <class T>
void init(T&& data) requires (sizeof(T) <= SOO_SIZE) {
// Let holder_ point to the reserved SOO block, and SOO optimization is activated
holder_ = reinterpret_cast<AbstractHolder*>(soo_block_);
// Call the constructor of the ConcreteHolder without memory allocation
new (reinterpret_cast<
ConcreteHolder<std::remove_reference_t<T>>*>(soo_block_))
ConcreteHolder<std::remove_reference_t<T>>(std::forward<T>(data));
}
/* Overload for large object */
template <class T>
void init(T&& data) requires (sizeof(T) > SOO_SIZE) {
// Let holder_ point to a "new" object, and SOO optimization is inactivated
holder_ = new ConcreteHolder<std::remove_reference_t<T>>(std::forward<T>(data));
}
/* Copy semantics */
void copy_init(deep_wrapper& rhs) const {
// There are two situations:
// 1. *this in invalid,
// rhs shall also be invalid.
// 2. *this is valid, no matter whether SOO optimization is activated,
// rhs shall be initialized with *this.
if (holder_ == nullptr) {
rhs.init();
} else {
holder_->copy_init(rhs);
}
}
/* Move semantics */
void move_init(deep_wrapper& rhs) {
// There are three situations:
// 1. *this in invalid,
// rhs shall also be invalid.
// 2. *this is valid and SSO optimization is activated,
// rhs shall be initialized with *this.
// 3. *this in valid and SSO optimization is inactivated,
// The pointer of the holder can be simply moved from *this to rhs.
if (holder_ == nullptr) {
rhs.init();
} else if ((char*)holder_ == soo_block_) {
holder_->move_init(rhs);
} else {
rhs.holder_ = holder_;
holder_ = nullptr;
}
}
/* Destroy semantics */
void deinit() {
// There are two situations:
// 1. SOO optimization is activated,
// The destructor of the holder shall be called without release the memory.
// 2. SOO optimization is inactivated,
// The pointer shall be deleted.
// If holder_ is a null pointer, this operation haves no side-effect.
if ((char*)holder_ == soo_block_) {
holder_->~AbstractHolder();
} else {
delete holder_;
}
}
/* Associates with the lifetime management strategy */
AbstractHolder* holder_;
/* A reserved block for SOO optimization */
char soo_block_[sizeof(AbstractHolder) + SOO_SIZE];
};
/* A wrapper that has nothing to do with the lifetime management issue */
class deferred_wrapper {
public:
/* Constructors */
template <class T>
deferred_wrapper(T&& data) requires
!std::is_same<raw_type<T>, deferred_wrapper>::value
{ data_ = (void*)&data; }
deferred_wrapper() = default;
deferred_wrapper(const deferred_wrapper&) = default;
deferred_wrapper(deferred_wrapper&&) = default;
deferred_wrapper& operator=(const deferred_wrapper&) = default;
deferred_wrapper& operator=(deferred_wrapper&&) = default;
/* Meets the Wrapper requirements */
void* get() { return data_; }
private:
void* data_;
};
/* A shared wrapper with "reference-counting" strategy for lifetime management */
class shared_wrapper {
public:
/* Constructors */
template <class T>
shared_wrapper(T&& data) requires
!std::is_same<raw_type<T>, shared_wrapper>::value
{ init(std::forward<T>(data)); }
shared_wrapper() { init(); }
shared_wrapper(const shared_wrapper& rhs) { rhs.copy_init(*this); }
shared_wrapper(shared_wrapper&& lhs) { lhs.move_init(*this); }
/* Destructor */
~shared_wrapper() { deinit(); }
shared_wrapper& operator=(const shared_wrapper& rhs) {
deinit();
rhs.copy_init(*this);
return *this;
}
shared_wrapper& operator=(shared_wrapper&& lhs) {
deinit();
lhs.move_init(*this);
return *this;
}
/* Meets the Wrapper requirements */
void* get() {
// The address of the wrapped object is calculated with a constant offset
return reinterpret_cast<char*>(holder_) + sizeof(AbstractHolder);
}
private:
class AbstractHolder {
public:
AbstractHolder() : count_(0u) {}
virtual ~AbstractHolder() {}
/* Different from usual implementations for "std::shared_ptr", reference count equals to "count_ - 1" here */
mutable std::atomic_size_t count_;
};
template <class T>
class ConcreteHolder : public AbstractHolder {
public:
template <class U>
ConcreteHolder(U&& data) : data_(std::forward<U>(data)) {}
private:
T data_;
};
void init() { holder_ = nullptr; }
/* Initialize with a concrete type and value */
template <class T>
void init(T&& data) {
// There is no requirement for extra synchronizations, so the memory order is relaxed
holder_ = new ConcreteHolder<std::remove_reference_t<T>>(std::forward<T>(data));
}
/* Copy semantics */
void copy_init(shared_wrapper& rhs) const {
rhs.holder_ = holder_;
holder_->count_.fetch_add(1u, std::memory_order_relaxed);
}
/* Move semantics */
void move_init(shared_wrapper& rhs) {
rhs.holder_ = holder_;
holder_ = nullptr;
}
/* Destroy semantics */
void deinit() {
// A release-acquire synchronization
// Every operation to the wrapped object happens before "delete holder_"
// This operation is similar with the "Atomic Counter" defined in P0642R0
if (holder_ != nullptr &&
holder_->count_.fetch_sub(1u, std::memory_order_release) == 0u) {
std::atomic_thread_fence(std::memory_order_acquire);
delete holder_;
}
}
AbstractHolder* holder_;
};
template <std::size_t SIZE>
class trivial_wrapper {
public:
/* Constructors */
template <class T>
trivial_wrapper(T&& data) requires
!std::is_same<raw_type<T>, trivial_wrapper>::value &&
std::is_trivial<raw_type<T>>::value &&
(sizeof(raw_type<T>) <= SIZE) {
memcpy(data_, &data, sizeof(raw_type<T>));
}
trivial_wrapper() = default;
trivial_wrapper(const trivial_wrapper&) = default;
trivial_wrapper(trivial_wrapper&&) = default;
trivial_wrapper& operator=(const trivial_wrapper& rhs) = default;
trivial_wrapper& operator=(trivial_wrapper&&) = default;
/* Meets the Wrapper requirements */
void* get() {
return data_;
}
private:
char data_[SIZE];
};
------=_Part_1580_1230667838.1498481030962--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 26 Jun 2017 08:54:52 -0700 (PDT)
Raw View
------=_Part_1818_1299046350.1498492492725
Content-Type: multipart/alternative;
boundary="----=_Part_1819_1688493101.1498492492725"
------=_Part_1819_1688493101.1498492492725
Content-Type: text/plain; charset="UTF-8"
You don't have to keep creating new threads to talk about the same
proposal. Just make a new post in your old one. The changes you've made
here are not substantial enough to warrant a new thread.
--
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/fe3e1350-775d-4c54-85a5-3d26cabb7f83%40isocpp.org.
------=_Part_1819_1688493101.1498492492725
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">You don't have to keep creating new threads to talk ab=
out the same proposal. Just make a new post in your old one. The changes yo=
u've made here are not substantial enough to warrant a new thread.<br><=
/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/fe3e1350-775d-4c54-85a5-3d26cabb7f83%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/fe3e1350-775d-4c54-85a5-3d26cabb7f83=
%40isocpp.org</a>.<br />
------=_Part_1819_1688493101.1498492492725--
------=_Part_1818_1299046350.1498492492725--
.