Is there a convenient way to re-assign the value of a unique_ptr
with a new owned object, without re-specifying the type?
For instance:
std::unique_ptr<int> foo;
// .... Later, once we actually have a value to store...
foo = std::make_unique<int>(my_cool_value);
Of course int
is not too much of an eyesore, but foo::element_type
could be long or subject to change after a refactoring.
So, to use type inference, we could do:
foo = std::make_unique<decltype(foo)::element_type>(value);
...But that's pretty hideous (foo::element_type
doesn't work because foo
can't be used in a constant expression).
Ideally, std::unique_ptr
would support a forwarding emplace
-like method:
foo.reassign(value);
This would release the old value and, just like std::vector::emplace
, construct the new owned object in-place.
....But as far as I can tell, there's nothing more concise than make_unique<decltype(foo)::element_type>
.
EDIT: The most concise way to reassign the value for a type that supports operator=
is, of course, to use operator=
:
*foo = value;`
...But I do not want to rely on the copyability of element_type
(for instance, I initially ran into this issue when trying to work with input-file streams).
Stash the arguments (or references thereto) into a proxy object with a templated conversion operator that deduces the target type. Then construct the new object once you have that deduced.
template<class... Args>
struct maker {
template<class T>
operator std::unique_ptr<T>() && {
return make<T>(std::index_sequence_for<Args...>());
}
std::tuple<Args...> args;
private:
template<class T, size_t ... Is>
std::unique_ptr<T> make(std::index_sequence<Is...>) {
return std::make_unique<T>(std::get<Is>(std::move(args))...);
}
};
template<class... Args>
auto maybe_make_unique_eventually(Args&&... args){
return maker<Args&&...>{std::forward_as_tuple(std::forward<Args>(args)...)};
}
It won't be a member function, but a free function could essentially achieve this:
template<typename T, typename D, typename...Args>
void TakeNew(std::unique_ptr<T,D>& up, Args&&... args)
{
up.reset(new T{std::forward<Args>(args)...});
// or use parentheses for consistency with `make_unique`; see comments
}
// usage...
auto foo = std::make_unique<int>(3);
// .... Later...
TakeNew(foo, 5);
(I do not consider this solution ideal.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With