#include <type_traits>
#include <utility>
template< typename T >
class clone_ptr_polymorph
{
void* mDerivedPtr;
T* mBasicPtr;
std::pair<T*, void*> (* mCloner)(void*);
template< typename Derived >
static std::pair<T*, void*> clone(void* ptr)
{
auto obj = new Derived{ *reinterpret_cast<Derived*>(ptr) };
return { obj, obj };
}
public:
template< typename Derived,
typename=typename std::enable_if<std::is_base_of<T, Derived>::value>::type >
clone_ptr_polymorph( Derived* ptr ) :
mDerivedPtr{ptr},
mBasicPtr{ptr},
mCloner{ &clone<Derived> } {}
clone_ptr_polymorph( clone_ptr_polymorph const& p ) :
mCloner{p.mCloner}
{
auto pair = mCloner(p.mDerivedPtr);
mBasicPtr = pair.first;
mDerivedPtr = pair.second;
}
~clone_ptr_polymorph()
{
delete mBasicPtr;
}
clone_ptr_polymorph( clone_ptr_polymorph&& ) = default;
clone_ptr_polymorph& operator=( clone_ptr_polymorph&& ) = default;
};
template<typename Base,
typename Der,
typename... Args>
clone_ptr_polymorph<Base> make_clone_ptr( Args&&... args )
{
return { new Der(std::forward<Args>(args)...) };
}
#include <iostream>
struct Base
{
virtual ~Base() { std::cout << "Base-Destructor\n"; }
Base() { std::cout << "Base-Def-Ctor\n"; }
Base(Base const&) { std::cout << "Base-Copy-Ctor\n"; }
Base(Base&&) { std::cout << "Base-Move-Ctor\n"; }
};
struct Derived : Base
{
~Derived() { std::cout << "Derived-Destructor\n"; }
Derived() { std::cout << "Derived-Def-Ctor\n"; }
Derived(Derived const&) { std::cout << "Derived-Copy-Ctor\n"; }
Derived(Derived&&) { std::cout << "Derived-Move-Ctor\n"; }
};
int main()
{
auto const& p = make_clone_ptr<Base, Derived>();
auto second = p;
}
I2luY2x1ZGUgPHR5cGVfdHJhaXRzPgojaW5jbHVkZSA8dXRpbGl0eT4KCnRlbXBsYXRlPCB0eXBlbmFtZSBUID4KY2xhc3MgY2xvbmVfcHRyX3BvbHltb3JwaAp7CiAgICB2b2lkKiBtRGVyaXZlZFB0cjsKICAgIFQqIG1CYXNpY1B0cjsKICAgIHN0ZDo6cGFpcjxUKiwgdm9pZCo+ICgqIG1DbG9uZXIpKHZvaWQqKTsgIAoKICAgIHRlbXBsYXRlPCB0eXBlbmFtZSBEZXJpdmVkID4KICAgIHN0YXRpYyBzdGQ6OnBhaXI8VCosIHZvaWQqPiBjbG9uZSh2b2lkKiBwdHIpCiAgICB7CiAgICAJYXV0byBvYmogPSBuZXcgRGVyaXZlZHsgKnJlaW50ZXJwcmV0X2Nhc3Q8RGVyaXZlZCo+KHB0cikgfTsKICAgIAlyZXR1cm4geyBvYmosIG9iaiB9OwogICAgfQogICAgCnB1YmxpYzoKICAgIHRlbXBsYXRlPCB0eXBlbmFtZSBEZXJpdmVkLAogICAgICAgICAgICAgIHR5cGVuYW1lPXR5cGVuYW1lIHN0ZDo6ZW5hYmxlX2lmPHN0ZDo6aXNfYmFzZV9vZjxULCBEZXJpdmVkPjo6dmFsdWU+Ojp0eXBlID4KICAgIGNsb25lX3B0cl9wb2x5bW9ycGgoIERlcml2ZWQqIHB0ciApIDoKICAgICAgICBtRGVyaXZlZFB0cntwdHJ9LAogICAgICAgIG1CYXNpY1B0cntwdHJ9LAogICAgICAgIG1DbG9uZXJ7ICZjbG9uZTxEZXJpdmVkPiB9IHt9CiAgICAgICAgCiAgICBjbG9uZV9wdHJfcG9seW1vcnBoKCBjbG9uZV9wdHJfcG9seW1vcnBoIGNvbnN0JiBwICkgOgogICAgICAgIG1DbG9uZXJ7cC5tQ2xvbmVyfQogICAgewogICAgCWF1dG8gcGFpciA9IG1DbG9uZXIocC5tRGVyaXZlZFB0cik7CiAgICAJbUJhc2ljUHRyID0gcGFpci5maXJzdDsKICAgIAltRGVyaXZlZFB0ciA9IHBhaXIuc2Vjb25kOwogICAgfQogICAgCiAgICB+Y2xvbmVfcHRyX3BvbHltb3JwaCgpCiAgICB7CiAgICAJZGVsZXRlIG1CYXNpY1B0cjsKICAgIH0KICAgIAogICAgY2xvbmVfcHRyX3BvbHltb3JwaCggY2xvbmVfcHRyX3BvbHltb3JwaCYmICkgPSBkZWZhdWx0OwogICAgY2xvbmVfcHRyX3BvbHltb3JwaCYgb3BlcmF0b3I9KCBjbG9uZV9wdHJfcG9seW1vcnBoJiYgKSA9IGRlZmF1bHQ7Cn07CiAgICAKdGVtcGxhdGU8dHlwZW5hbWUgQmFzZSwKICAgICAgICAgdHlwZW5hbWUgRGVyLAogICAgICAgICB0eXBlbmFtZS4uLiBBcmdzPgpjbG9uZV9wdHJfcG9seW1vcnBoPEJhc2U+IG1ha2VfY2xvbmVfcHRyKCBBcmdzJiYuLi4gYXJncyApCnsKCXJldHVybiB7IG5ldyBEZXIoc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpLi4uKSB9Owp9CgojaW5jbHVkZSA8aW9zdHJlYW0+CgpzdHJ1Y3QgQmFzZQp7Cgl2aXJ0dWFsIH5CYXNlKCkgeyBzdGQ6OmNvdXQgPDwgIkJhc2UtRGVzdHJ1Y3RvclxuIjsgfQoJQmFzZSgpIHsgc3RkOjpjb3V0IDw8ICJCYXNlLURlZi1DdG9yXG4iOyB9CglCYXNlKEJhc2UgY29uc3QmKSB7IHN0ZDo6Y291dCA8PCAiQmFzZS1Db3B5LUN0b3JcbiI7IH0KCUJhc2UoQmFzZSYmKSB7IHN0ZDo6Y291dCA8PCAiQmFzZS1Nb3ZlLUN0b3JcbiI7IH0KfTsKCnN0cnVjdCBEZXJpdmVkIDogQmFzZQp7Cgl+RGVyaXZlZCgpIHsgc3RkOjpjb3V0IDw8ICJEZXJpdmVkLURlc3RydWN0b3JcbiI7IH0KCURlcml2ZWQoKSB7IHN0ZDo6Y291dCA8PCAiRGVyaXZlZC1EZWYtQ3RvclxuIjsgfQoJRGVyaXZlZChEZXJpdmVkIGNvbnN0JikgeyBzdGQ6OmNvdXQgPDwgIkRlcml2ZWQtQ29weS1DdG9yXG4iOyB9CglEZXJpdmVkKERlcml2ZWQmJikgeyBzdGQ6OmNvdXQgPDwgIkRlcml2ZWQtTW92ZS1DdG9yXG4iOyB9Cn07CgppbnQgbWFpbigpCnsKCWF1dG8gY29uc3QmIHAgPSBtYWtlX2Nsb25lX3B0cjxCYXNlLCBEZXJpdmVkPigpOwoJYXV0byBzZWNvbmQgPSBwOwp9CgogICAg