#include <type_traits>
#include <memory>
#include <iostream>
namespace detail
{
template <typename T>
struct wrapper
{
virtual ~wrapper() {}
virtual T const * get() const = 0;
virtual T * get() = 0;
};
template <typename T, typename F>
struct storage
: wrapper<T>
{
storage(F f)
{
p_ = f();
}
T const * get() const { return p_.get(); }
T * get() { return p_.get(); }
private:
typename std::result_of<F()>::type p_;
};
}
template <typename T>
class some_class
{
public:
template <typename F>
void store(F f)
{
storage_.reset(new detail::storage<T, F>(f));
}
T const * get() const { return storage_->get(); }
T * get() { return storage_->get(); }
private:
std::unique_ptr<detail::wrapper<T>> storage_;
};
struct foo
{
void bar() const { std::cout << "hello" << '\n'; }
};
int main()
{
some_class<foo> a;
a.store([]() { return std::unique_ptr<foo>(new foo()); });
a.get()->bar();
a.store([]() { return std::unique_ptr<
foo, std::default_delete<foo[]>
>(new foo[1], std::default_delete<foo[]>()); });
a.get()[0].bar();
return 0;
}
I2luY2x1ZGUgPHR5cGVfdHJhaXRzPgojaW5jbHVkZSA8bWVtb3J5PgojaW5jbHVkZSA8aW9zdHJlYW0+CgpuYW1lc3BhY2UgZGV0YWlsCnsKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUPgogICAgc3RydWN0IHdyYXBwZXIKICAgIHsKICAgICAgICB2aXJ0dWFsIH53cmFwcGVyKCkge30KICAgICAgICB2aXJ0dWFsIFQgY29uc3QgKiBnZXQoKSBjb25zdCA9IDA7CiAgICAgICAgdmlydHVhbCBUICogZ2V0KCkgPSAwOwogICAgfTsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdHlwZW5hbWUgRj4KICAgIHN0cnVjdCBzdG9yYWdlCiAgICAgICAgOiB3cmFwcGVyPFQ+CiAgICB7CiAgICAgICAgc3RvcmFnZShGIGYpCiAgICAgICAgewogICAgICAgICAgICBwXyA9IGYoKTsKICAgICAgICB9CgogICAgICAgIFQgY29uc3QgKiBnZXQoKSBjb25zdCB7IHJldHVybiBwXy5nZXQoKTsgfQogICAgICAgIFQgKiBnZXQoKSB7IHJldHVybiBwXy5nZXQoKTsgfQoKICAgICAgICBwcml2YXRlOgogICAgICAgICAgICB0eXBlbmFtZSBzdGQ6OnJlc3VsdF9vZjxGKCk+Ojp0eXBlIHBfOwogICAgfTsKfQoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CmNsYXNzIHNvbWVfY2xhc3MKewogICAgcHVibGljOgogICAgICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBGPgogICAgICAgIHZvaWQgc3RvcmUoRiBmKQogICAgICAgIHsKICAgICAgICAgICAgc3RvcmFnZV8ucmVzZXQobmV3IGRldGFpbDo6c3RvcmFnZTxULCBGPihmKSk7CiAgICAgICAgfQoKICAgICAgICBUIGNvbnN0ICogZ2V0KCkgY29uc3QgeyByZXR1cm4gc3RvcmFnZV8tPmdldCgpOyB9CiAgICAgICAgVCAqIGdldCgpIHsgcmV0dXJuIHN0b3JhZ2VfLT5nZXQoKTsgfQoKICAgIHByaXZhdGU6CiAgICAgICAgc3RkOjp1bmlxdWVfcHRyPGRldGFpbDo6d3JhcHBlcjxUPj4gc3RvcmFnZV87Cn07CgpzdHJ1Y3QgZm9vCnsKICAgIHZvaWQgYmFyKCkgY29uc3QgeyBzdGQ6OmNvdXQgPDwgImhlbGxvIiA8PCAnXG4nOyB9Cn07CgppbnQgbWFpbigpCnsKICAgIHNvbWVfY2xhc3M8Zm9vPiBhOwogICAgYS5zdG9yZShbXSgpIHsgcmV0dXJuIHN0ZDo6dW5pcXVlX3B0cjxmb28+KG5ldyBmb28oKSk7IH0pOwogICAgYS5nZXQoKS0+YmFyKCk7CiAgICBhLnN0b3JlKFtdKCkgeyByZXR1cm4gc3RkOjp1bmlxdWVfcHRyPAogICAgICAgIGZvbywgc3RkOjpkZWZhdWx0X2RlbGV0ZTxmb29bXT4KICAgID4obmV3IGZvb1sxXSwgc3RkOjpkZWZhdWx0X2RlbGV0ZTxmb29bXT4oKSk7IH0pOwogICAgYS5nZXQoKVswXS5iYXIoKTsKCiAgICByZXR1cm4gMDsKfQ==